@agentuity/workbench 0.0.104 → 0.0.106

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 (169) hide show
  1. package/dist/components/App.d.ts.map +1 -1
  2. package/dist/components/App.js +15 -13
  3. package/dist/components/App.js.map +1 -1
  4. package/dist/components/ai-elements/actions.d.ts +1 -1
  5. package/dist/components/ai-elements/actions.d.ts.map +1 -1
  6. package/dist/components/ai-elements/actions.js +1 -1
  7. package/dist/components/ai-elements/actions.js.map +1 -1
  8. package/dist/components/ai-elements/code-block.d.ts +1 -1
  9. package/dist/components/ai-elements/code-block.d.ts.map +1 -1
  10. package/dist/components/ai-elements/code-block.js +22 -20
  11. package/dist/components/ai-elements/code-block.js.map +1 -1
  12. package/dist/components/ai-elements/conversation.d.ts +2 -2
  13. package/dist/components/ai-elements/conversation.d.ts.map +1 -1
  14. package/dist/components/ai-elements/conversation.js +5 -3
  15. package/dist/components/ai-elements/conversation.js.map +1 -1
  16. package/dist/components/ai-elements/message.d.ts +1 -1
  17. package/dist/components/ai-elements/message.d.ts.map +1 -1
  18. package/dist/components/ai-elements/message.js +4 -9
  19. package/dist/components/ai-elements/message.js.map +1 -1
  20. package/dist/components/ai-elements/prompt-input.d.ts.map +1 -1
  21. package/dist/components/ai-elements/prompt-input.js +1 -1
  22. package/dist/components/ai-elements/prompt-input.js.map +1 -1
  23. package/dist/components/ai-elements/shimmer.d.ts.map +1 -1
  24. package/dist/components/ai-elements/shimmer.js +1 -1
  25. package/dist/components/ai-elements/shimmer.js.map +1 -1
  26. package/dist/components/internal/chat.d.ts +10 -0
  27. package/dist/components/internal/chat.d.ts.map +1 -0
  28. package/dist/components/internal/chat.js +104 -0
  29. package/dist/components/internal/chat.js.map +1 -0
  30. package/dist/components/internal/{Header.d.ts → header.d.ts} +4 -6
  31. package/dist/components/internal/header.d.ts.map +1 -0
  32. package/dist/components/internal/header.js +25 -0
  33. package/dist/components/internal/header.js.map +1 -0
  34. package/dist/components/internal/{InputSection.d.ts → input-section.d.ts} +9 -9
  35. package/dist/components/internal/input-section.d.ts.map +1 -0
  36. package/dist/components/internal/{InputSection.js → input-section.js} +36 -25
  37. package/dist/components/internal/input-section.js.map +1 -0
  38. package/dist/components/internal/json-editor.d.ts +14 -0
  39. package/dist/components/internal/json-editor.d.ts.map +1 -0
  40. package/dist/components/internal/{MonacoJsonEditor.js → json-editor.js} +40 -37
  41. package/dist/components/internal/json-editor.js.map +1 -0
  42. package/dist/components/internal/logo.d.ts +2 -3
  43. package/dist/components/internal/logo.d.ts.map +1 -1
  44. package/dist/components/internal/logo.js +2 -2
  45. package/dist/components/internal/logo.js.map +1 -1
  46. package/dist/components/internal/resizable-provider.d.ts.map +1 -0
  47. package/dist/components/internal/resizable-provider.js.map +1 -0
  48. package/dist/components/internal/{Schema.d.ts → schema.d.ts} +1 -1
  49. package/dist/components/internal/schema.d.ts.map +1 -0
  50. package/dist/components/internal/schema.js +13 -0
  51. package/dist/components/internal/schema.js.map +1 -0
  52. package/dist/components/internal/{WorkbenchProvider.d.ts → workbench-provider.d.ts} +8 -4
  53. package/dist/components/internal/workbench-provider.d.ts.map +1 -0
  54. package/dist/components/internal/{WorkbenchProvider.js → workbench-provider.js} +58 -39
  55. package/dist/components/internal/workbench-provider.js.map +1 -0
  56. package/dist/components/ui/avatar.d.ts +1 -1
  57. package/dist/components/ui/avatar.d.ts.map +1 -1
  58. package/dist/components/ui/avatar.js.map +1 -1
  59. package/dist/components/ui/button.d.ts +1 -1
  60. package/dist/components/ui/command.d.ts +1 -1
  61. package/dist/components/ui/command.d.ts.map +1 -1
  62. package/dist/components/ui/command.js.map +1 -1
  63. package/dist/components/ui/dialog.d.ts +1 -1
  64. package/dist/components/ui/dialog.d.ts.map +1 -1
  65. package/dist/components/ui/dialog.js.map +1 -1
  66. package/dist/components/ui/dropdown-menu.d.ts +1 -1
  67. package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
  68. package/dist/components/ui/dropdown-menu.js.map +1 -1
  69. package/dist/components/ui/hover-card.d.ts +1 -1
  70. package/dist/components/ui/hover-card.d.ts.map +1 -1
  71. package/dist/components/ui/hover-card.js.map +1 -1
  72. package/dist/components/ui/input-group.d.ts +2 -2
  73. package/dist/components/ui/input-group.d.ts.map +1 -1
  74. package/dist/components/ui/input-group.js.map +1 -1
  75. package/dist/components/ui/input.d.ts +1 -1
  76. package/dist/components/ui/input.d.ts.map +1 -1
  77. package/dist/components/ui/scroll-area.d.ts +1 -1
  78. package/dist/components/ui/scroll-area.d.ts.map +1 -1
  79. package/dist/components/ui/scroll-area.js.map +1 -1
  80. package/dist/components/ui/textarea.d.ts +1 -1
  81. package/dist/components/ui/textarea.d.ts.map +1 -1
  82. package/dist/components/ui/theme-provider.d.ts.map +1 -1
  83. package/dist/components/ui/theme-provider.js +1 -1
  84. package/dist/components/ui/theme-provider.js.map +1 -1
  85. package/dist/components/ui/tooltip.d.ts +1 -1
  86. package/dist/components/ui/tooltip.d.ts.map +1 -1
  87. package/dist/components/ui/tooltip.js.map +1 -1
  88. package/dist/hooks/useAgentSchemas.d.ts +10 -10
  89. package/dist/hooks/useAgentSchemas.d.ts.map +1 -1
  90. package/dist/hooks/useAgentSchemas.js +5 -5
  91. package/dist/hooks/useAgentSchemas.js.map +1 -1
  92. package/dist/hooks/useLogger.d.ts.map +1 -1
  93. package/dist/hooks/useLogger.js +2 -1
  94. package/dist/hooks/useLogger.js.map +1 -1
  95. package/dist/hooks/useWorkbenchWebsocket.d.ts +2 -2
  96. package/dist/hooks/useWorkbenchWebsocket.d.ts.map +1 -1
  97. package/dist/hooks/useWorkbenchWebsocket.js +24 -20
  98. package/dist/hooks/useWorkbenchWebsocket.js.map +1 -1
  99. package/dist/index.d.ts +5 -5
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +4 -6
  102. package/dist/index.js.map +1 -1
  103. package/dist/lib/utils.d.ts +3 -0
  104. package/dist/lib/utils.d.ts.map +1 -1
  105. package/dist/lib/utils.js +59 -0
  106. package/dist/lib/utils.js.map +1 -1
  107. package/dist/server.d.ts +1 -1
  108. package/dist/server.d.ts.map +1 -1
  109. package/dist/server.js.map +1 -1
  110. package/dist/standalone.css +355 -298
  111. package/dist/types/config.d.ts +27 -18
  112. package/dist/types/config.d.ts.map +1 -1
  113. package/package.json +5 -5
  114. package/src/base.css +186 -158
  115. package/src/components/App.tsx +31 -16
  116. package/src/components/ai-elements/actions.tsx +2 -2
  117. package/src/components/ai-elements/code-block.tsx +46 -32
  118. package/src/components/ai-elements/conversation.tsx +18 -17
  119. package/src/components/ai-elements/message.tsx +4 -9
  120. package/src/components/ai-elements/prompt-input.tsx +1 -1
  121. package/src/components/ai-elements/shimmer.tsx +1 -1
  122. package/src/components/internal/chat.tsx +324 -0
  123. package/src/components/internal/{Header.tsx → header.tsx} +37 -40
  124. package/src/components/internal/{InputSection.tsx → input-section.tsx} +169 -115
  125. package/src/components/internal/{MonacoJsonEditor.tsx → json-editor.tsx} +77 -49
  126. package/src/components/internal/logo.tsx +3 -5
  127. package/src/components/internal/{Schema.tsx → schema.tsx} +28 -34
  128. package/src/components/internal/{WorkbenchProvider.tsx → workbench-provider.tsx} +156 -48
  129. package/src/components/ui/avatar.tsx +1 -1
  130. package/src/components/ui/command.tsx +1 -1
  131. package/src/components/ui/dialog.tsx +1 -1
  132. package/src/components/ui/dropdown-menu.tsx +1 -1
  133. package/src/components/ui/hover-card.tsx +1 -1
  134. package/src/components/ui/input-group.tsx +1 -1
  135. package/src/components/ui/input.tsx +1 -1
  136. package/src/components/ui/scroll-area.tsx +1 -1
  137. package/src/components/ui/textarea.tsx +1 -1
  138. package/src/components/ui/theme-provider.tsx +1 -1
  139. package/src/components/ui/tooltip.tsx +1 -1
  140. package/src/hooks/useAgentSchemas.ts +22 -13
  141. package/src/hooks/useLogger.ts +7 -1
  142. package/src/hooks/useWorkbenchWebsocket.ts +67 -32
  143. package/src/index.ts +5 -9
  144. package/src/lib/utils.ts +88 -0
  145. package/src/server.ts +1 -1
  146. package/src/types/config.ts +28 -21
  147. package/dist/components/internal/Chat.d.ts +0 -14
  148. package/dist/components/internal/Chat.d.ts.map +0 -1
  149. package/dist/components/internal/Chat.js +0 -61
  150. package/dist/components/internal/Chat.js.map +0 -1
  151. package/dist/components/internal/Header.d.ts.map +0 -1
  152. package/dist/components/internal/Header.js +0 -31
  153. package/dist/components/internal/Header.js.map +0 -1
  154. package/dist/components/internal/InputSection.d.ts.map +0 -1
  155. package/dist/components/internal/InputSection.js.map +0 -1
  156. package/dist/components/internal/MonacoJsonEditor.d.ts +0 -13
  157. package/dist/components/internal/MonacoJsonEditor.d.ts.map +0 -1
  158. package/dist/components/internal/MonacoJsonEditor.js.map +0 -1
  159. package/dist/components/internal/Schema.d.ts.map +0 -1
  160. package/dist/components/internal/Schema.js +0 -13
  161. package/dist/components/internal/Schema.js.map +0 -1
  162. package/dist/components/internal/WorkbenchProvider.d.ts.map +0 -1
  163. package/dist/components/internal/WorkbenchProvider.js.map +0 -1
  164. package/dist/components/ui/resizable-provider.d.ts.map +0 -1
  165. package/dist/components/ui/resizable-provider.js.map +0 -1
  166. package/src/components/internal/Chat.tsx +0 -201
  167. /package/dist/components/{ui → internal}/resizable-provider.d.ts +0 -0
  168. /package/dist/components/{ui → internal}/resizable-provider.js +0 -0
  169. /package/src/components/{ui → internal}/resizable-provider.tsx +0 -0
@@ -1,19 +1,22 @@
1
- import React, { createContext, useContext, useEffect, useState, useCallback } from 'react';
2
- import type { UIMessage } from 'ai';
3
1
  import type { WorkbenchConfig } from '@agentuity/core/workbench';
4
- import type { WorkbenchContextType, ConnectionStatus } from '../../types/config';
2
+ import type { UIMessage } from 'ai';
3
+ import type React from 'react';
4
+ import { createContext, useCallback, useContext, useEffect, useState } from 'react';
5
5
  import { useAgentSchemas } from '../../hooks/useAgentSchemas';
6
- import { useWorkbenchWebsocket } from '../../hooks/useWorkbenchWebsocket';
7
6
  import { useLogger } from '../../hooks/useLogger';
8
- import { getTotalTokens, parseTokensHeader, defaultBaseUrl } from '../../lib/utils';
7
+ import { useWorkbenchWebsocket } from '../../hooks/useWorkbenchWebsocket';
8
+ import { defaultBaseUrl, getTotalTokens, parseTokensHeader } from '../../lib/utils';
9
+ import type { ConnectionStatus, WorkbenchContextType } from '../../types/config';
9
10
 
10
11
  const WorkbenchContext = createContext<WorkbenchContextType | null>(null);
11
12
 
12
13
  export function useWorkbench() {
13
14
  const context = useContext(WorkbenchContext);
15
+
14
16
  if (!context) {
15
17
  throw new Error('useWorkbench must be used within a WorkbenchProvider');
16
18
  }
19
+
17
20
  return context;
18
21
  }
19
22
 
@@ -22,23 +25,35 @@ interface WorkbenchProviderProps {
22
25
  baseUrl?: string | null;
23
26
  projectId?: string;
24
27
  };
25
- isAuthenticated: boolean;
28
+ env: {
29
+ agentuity: boolean;
30
+ authenticated: boolean;
31
+ cloud: boolean;
32
+ };
26
33
  children: React.ReactNode;
27
34
  }
28
35
 
29
- export function WorkbenchProvider({ config, isAuthenticated, children }: WorkbenchProviderProps) {
36
+ export function WorkbenchProvider({
37
+ config,
38
+ env = {
39
+ agentuity: false,
40
+ authenticated: false,
41
+ cloud: false,
42
+ },
43
+ children,
44
+ }: WorkbenchProviderProps) {
30
45
  const logger = useLogger('WorkbenchProvider');
31
-
32
46
  // localStorage utilities scoped by project
33
47
  const getStorageKey = useCallback(
34
- (key: string) => `agentuity_workbench_${config.projectId}_${key}`,
48
+ (key: string) =>
49
+ `agentuity-workbench-${config.projectId ? `${config.projectId}-` : ''}${key}`,
35
50
  [config.projectId]
36
51
  );
37
52
 
38
53
  const saveSelectedAgent = useCallback(
39
54
  (agentId: string) => {
40
55
  try {
41
- localStorage.setItem(getStorageKey('selected_agent'), agentId);
56
+ localStorage.setItem(getStorageKey('selected-agent'), agentId);
42
57
  } catch (error) {
43
58
  console.warn('Failed to save selected agent to localStorage:', error);
44
59
  }
@@ -48,7 +63,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
48
63
 
49
64
  const loadSelectedAgent = useCallback((): string | null => {
50
65
  try {
51
- return localStorage.getItem(getStorageKey('selected_agent'));
66
+ return localStorage.getItem(getStorageKey('selected-agent'));
52
67
  } catch (error) {
53
68
  console.warn('Failed to load selected agent from localStorage:', error);
54
69
  return null;
@@ -58,7 +73,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
58
73
  const saveThreadId = useCallback(
59
74
  (threadId: string) => {
60
75
  try {
61
- localStorage.setItem(getStorageKey('thread_id'), threadId);
76
+ localStorage.setItem(getStorageKey('thread-id'), threadId);
62
77
  } catch (error) {
63
78
  console.warn('Failed to save thread id to localStorage:', error);
64
79
  }
@@ -68,7 +83,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
68
83
 
69
84
  const loadThreadId = useCallback((): string | null => {
70
85
  try {
71
- return localStorage.getItem(getStorageKey('thread_id'));
86
+ return localStorage.getItem(getStorageKey('thread-id'));
72
87
  } catch (error) {
73
88
  console.warn('Failed to load thread id from localStorage:', error);
74
89
  return null;
@@ -120,6 +135,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
120
135
  useEffect(() => {
121
136
  if (isBaseUrlNull) {
122
137
  logger.debug('🔌 Setting connection status to disconnected (baseUrl is null)');
138
+
123
139
  setConnectionStatus('disconnected');
124
140
  }
125
141
  }, [isBaseUrlNull, logger]);
@@ -143,6 +159,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
143
159
 
144
160
  // WebSocket connection for dev server restart detection
145
161
  const wsBaseUrl = isBaseUrlNull ? undefined : baseUrl;
162
+
146
163
  useEffect(() => {
147
164
  if (isBaseUrlNull) {
148
165
  logger.debug('🔌 WebSocket connection disabled (baseUrl is null)');
@@ -178,6 +195,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
178
195
 
179
196
  // Convert schema data to Agent format, no fallback
180
197
  const agents = schemaData?.agents;
198
+
181
199
  // Log schema fetch errors for debugging
182
200
  useEffect(() => {
183
201
  if (schemasError) {
@@ -188,8 +206,6 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
188
206
  }
189
207
  }, [schemasError]);
190
208
 
191
- const [suggestions, _setSuggestions] = useState<string[]>([]);
192
-
193
209
  // Fetch state for an agent
194
210
  const fetchAgentState = useCallback(
195
211
  async (agentId: string) => {
@@ -205,18 +221,23 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
205
221
 
206
222
  try {
207
223
  const headers: Record<string, string> = {};
224
+
208
225
  if (apiKey) {
209
226
  headers.Authorization = `Bearer ${apiKey}`;
210
227
  }
228
+
211
229
  applyThreadIdHeader(headers);
212
230
 
213
231
  const url = `${baseUrl}/_agentuity/workbench/state?agentId=${encodeURIComponent(agentId)}`;
232
+
214
233
  logger.debug('📡 Fetching state for agent:', agentId);
234
+
215
235
  const response = await fetch(url, {
216
236
  method: 'GET',
217
237
  headers,
218
238
  credentials: 'include',
219
239
  });
240
+
220
241
  persistThreadIdFromResponse(response);
221
242
 
222
243
  if (response.ok) {
@@ -233,8 +254,10 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
233
254
  typeof msg.data === 'object'
234
255
  ? JSON.stringify(msg.data, null, 2)
235
256
  : String(msg.data);
257
+
236
258
  // Use stable ID based on index and a hash of content to maintain identity
237
259
  const contentHash = text.substring(0, 20).replace(/[^a-zA-Z0-9]/g, '');
260
+
238
261
  return {
239
262
  id: `state_${agentId}_${index}_${contentHash}`,
240
263
  role: msg.type === 'input' ? 'user' : 'assistant',
@@ -243,13 +266,16 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
243
266
  });
244
267
 
245
268
  setMessages(uiMessages);
269
+
246
270
  logger.debug('✅ Loaded state messages:', uiMessages.length);
247
271
  } else {
248
272
  logger.debug('⚠️ Failed to fetch state, starting with empty messages');
273
+
249
274
  setMessages([]);
250
275
  }
251
276
  } catch (error) {
252
277
  logger.debug('⚠️ Error fetching state:', error);
278
+
253
279
  setMessages([]);
254
280
  }
255
281
  },
@@ -264,16 +290,20 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
264
290
  // First, check for agent query parameter in URL
265
291
  const urlParams = new URLSearchParams(window.location.search);
266
292
  const agentFromUrl = urlParams.get('agent');
293
+
267
294
  logger.debug('🔗 Agent from URL query param:', agentFromUrl);
268
295
 
269
296
  // Try to find agent by URL param (matches agentId only)
270
297
  let agentToSelect: string | null = null;
298
+
271
299
  if (agentFromUrl) {
272
300
  const matchedAgent = Object.values(agents).find(
273
301
  (agent) => agent.metadata.agentId === agentFromUrl
274
302
  );
303
+
275
304
  if (matchedAgent) {
276
305
  logger.debug('✅ Found agent from URL param:', matchedAgent.metadata.name);
306
+
277
307
  agentToSelect = matchedAgent.metadata.agentId;
278
308
  }
279
309
  }
@@ -281,6 +311,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
281
311
  // If no URL param match, try localStorage
282
312
  if (!agentToSelect) {
283
313
  const savedAgentId = loadSelectedAgent();
314
+
284
315
  logger.debug('💾 Saved agent from localStorage:', savedAgentId);
285
316
 
286
317
  const savedAgent = savedAgentId
@@ -289,6 +320,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
289
320
 
290
321
  if (savedAgent && savedAgentId) {
291
322
  logger.debug('✅ Restoring saved agent:', savedAgent.metadata.name);
323
+
292
324
  agentToSelect = savedAgentId;
293
325
  }
294
326
  }
@@ -298,44 +330,44 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
298
330
  const sortedAgents = Object.values(agents).sort((a, b) =>
299
331
  a.metadata.name.localeCompare(b.metadata.name)
300
332
  );
333
+
301
334
  const firstAgent = sortedAgents[0];
335
+
302
336
  logger.debug(
303
337
  '🎯 No saved agent found, using first agent (alphabetically):',
304
338
  firstAgent
305
339
  );
340
+
306
341
  agentToSelect = firstAgent.metadata.agentId;
307
342
  }
308
343
 
309
344
  logger.debug('🆔 Setting selectedAgent to:', agentToSelect);
345
+
310
346
  setSelectedAgent(agentToSelect);
311
347
  saveSelectedAgent(agentToSelect);
312
348
  fetchAgentState(agentToSelect);
313
349
  }
314
350
  }, [agents, selectedAgent, loadSelectedAgent, saveSelectedAgent, logger, fetchAgentState]);
315
351
 
316
- // Fetch suggestions from API if endpoint is provided
317
- useEffect(() => {
318
- // No API endpoints hardcoded for now
319
- }, []);
320
-
321
- const _fetchSuggestions = async () => {
322
- // No API endpoints for now
323
- };
324
-
325
352
  const submitMessage = async (value: string, _mode: 'text' | 'form' = 'text') => {
326
353
  if (!selectedAgent) return;
327
354
 
328
355
  logger.debug('🚀 Submitting message with selectedAgent:', selectedAgent);
356
+
329
357
  const selectedAgentData = agents
330
358
  ? Object.values(agents).find((agent) => agent.metadata.agentId === selectedAgent)
331
359
  : undefined;
360
+
332
361
  logger.debug('📊 Found selectedAgentData:', selectedAgentData);
362
+
333
363
  const hasInputSchema = selectedAgentData?.schema?.input?.json;
364
+
334
365
  logger.debug('📝 hasInputSchema:', hasInputSchema, 'value:', value);
335
366
 
336
367
  // Only require value for agents with input schemas
337
368
  if (hasInputSchema && !value.trim()) {
338
369
  logger.debug('❌ Returning early - hasInputSchema but no value');
370
+
339
371
  return;
340
372
  }
341
373
 
@@ -353,7 +385,6 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
353
385
  role: 'user',
354
386
  parts: [{ type: 'text', text: displayText }],
355
387
  };
356
-
357
388
  const assistantMessageId = (now + 1).toString();
358
389
  const placeholderAssistantMessage: UIMessage = {
359
390
  id: assistantMessageId,
@@ -365,8 +396,10 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
365
396
  setIsLoading(true);
366
397
 
367
398
  logger.debug('🔗 baseUrl:', baseUrl, 'isBaseUrlNull:', isBaseUrlNull);
399
+
368
400
  if (!baseUrl || isBaseUrlNull) {
369
401
  logger.debug('❌ Message submission blocked - baseUrl is null or missing');
402
+
370
403
  const errorMessage: UIMessage = {
371
404
  id: assistantMessageId,
372
405
  role: 'assistant',
@@ -377,8 +410,11 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
377
410
  },
378
411
  ],
379
412
  };
413
+
380
414
  setMessages((prev) => prev.map((m) => (m.id === assistantMessageId ? errorMessage : m)));
415
+
381
416
  setIsLoading(false);
417
+
382
418
  return;
383
419
  }
384
420
 
@@ -386,6 +422,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
386
422
  // Parse input - if it's JSON, parse it, otherwise use as string
387
423
  // For agents without input schema, send undefined
388
424
  let parsedInput: unknown;
425
+
389
426
  if (!hasInputSchema) {
390
427
  parsedInput = undefined;
391
428
  } else {
@@ -397,18 +434,20 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
397
434
  }
398
435
 
399
436
  logger.debug('🌐 About to make API call...');
437
+
400
438
  // Call execution endpoint with timeout
401
439
  const headers: Record<string, string> = {
402
440
  'Content-Type': 'application/json',
403
441
  };
442
+
404
443
  if (apiKey) {
405
444
  headers.Authorization = `Bearer ${apiKey}`;
406
445
  }
446
+
407
447
  applyThreadIdHeader(headers);
408
448
 
409
449
  const controller = new AbortController();
410
450
  const timeoutId = setTimeout(() => controller.abort(), 30000); // 30s timeout
411
-
412
451
  const startTime = performance.now();
413
452
 
414
453
  try {
@@ -416,7 +455,9 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
416
455
  agentId: selectedAgent,
417
456
  input: parsedInput,
418
457
  };
458
+
419
459
  logger.debug('📤 API Request payload:', requestPayload);
460
+
420
461
  const response = await fetch(`${baseUrl}/_agentuity/workbench/execute`, {
421
462
  method: 'POST',
422
463
  headers,
@@ -424,24 +465,29 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
424
465
  signal: controller.signal,
425
466
  credentials: 'include',
426
467
  });
468
+
427
469
  persistThreadIdFromResponse(response);
428
470
  clearTimeout(timeoutId);
429
471
 
430
472
  if (!response.ok) {
431
473
  let errorMessage = `Request failed with status ${response.status}`;
474
+
432
475
  try {
433
476
  const errorData = await response.json();
477
+
434
478
  errorMessage = errorData.error || errorData.message || errorMessage;
435
479
  } catch {
436
480
  // If JSON parsing fails, use status text
437
481
  errorMessage = response.statusText || errorMessage;
438
482
  }
483
+
439
484
  throw new Error(errorMessage);
440
485
  }
441
486
 
442
- let result;
487
+ let responseBody: unknown;
488
+
443
489
  try {
444
- result = await response.json();
490
+ responseBody = await response.json();
445
491
  } catch (jsonError) {
446
492
  throw new Error(`Invalid JSON response from server: ${jsonError}`);
447
493
  }
@@ -458,16 +504,66 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
458
504
  const tokensRecord = tokensHeader ? parseTokensHeader(tokensHeader) : undefined;
459
505
  const totalTokens = tokensRecord ? getTotalTokens(tokensRecord) : undefined;
460
506
 
507
+ // Handle wrapped response shape: { success, data?, error? }
508
+ const envelope =
509
+ typeof responseBody === 'object' && responseBody !== null
510
+ ? (responseBody as {
511
+ success?: boolean;
512
+ data?: unknown;
513
+ error?: {
514
+ message?: string;
515
+ stack?: string;
516
+ code?: string;
517
+ cause?: unknown;
518
+ };
519
+ })
520
+ : null;
521
+
522
+ if (envelope && 'success' in envelope && envelope.success === false && envelope.error) {
523
+ // Agent execution error - encode as special JSON format for ErrorBubble
524
+ const errorPayload = JSON.stringify({
525
+ __agentError: true,
526
+ message: envelope.error.message || 'Unknown error',
527
+ stack: envelope.error.stack,
528
+ code: envelope.error.code,
529
+ cause: envelope.error.cause,
530
+ });
531
+
532
+ const errorMessage: UIMessage = {
533
+ id: assistantMessageId,
534
+ role: 'assistant',
535
+ parts: [{ type: 'text', text: errorPayload }],
536
+ };
537
+
538
+ setMessages((prev) =>
539
+ prev.map((m) => (m.id === assistantMessageId ? errorMessage : m))
540
+ );
541
+ return;
542
+ }
543
+
544
+ // Success - extract data from envelope (or use raw response if not wrapped)
545
+ const result =
546
+ envelope && 'success' in envelope && envelope.success === true
547
+ ? envelope.data
548
+ : responseBody;
549
+
461
550
  // Format result as JSON string for display
462
551
  const resultText =
463
552
  typeof result === 'object' ? JSON.stringify(result, null, 2) : String(result);
464
553
 
465
- const assistantMessage: UIMessage & { tokens?: string; duration?: string } = {
554
+ const sessionId = response.headers.get('x-session-id') || undefined;
555
+
556
+ const assistantMessage: UIMessage & {
557
+ tokens?: string;
558
+ duration?: string;
559
+ sessionId?: string;
560
+ } = {
466
561
  id: assistantMessageId,
467
562
  role: 'assistant',
468
563
  parts: [{ type: 'text', text: resultText }],
469
564
  tokens: totalTokens?.toString(),
470
565
  duration,
566
+ sessionId,
471
567
  };
472
568
 
473
569
  setMessages((prev) =>
@@ -475,10 +571,12 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
475
571
  );
476
572
  } catch (fetchError) {
477
573
  clearTimeout(timeoutId);
574
+
478
575
  throw fetchError;
479
576
  }
480
577
  } catch (error) {
481
578
  console.error('Failed to submit message:', error);
579
+
482
580
  const errorText =
483
581
  error instanceof Error
484
582
  ? error.name === 'AbortError'
@@ -496,6 +594,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
496
594
  },
497
595
  ],
498
596
  };
597
+
499
598
  setMessages((prev) => prev.map((m) => (m.id === assistantMessageId ? errorMessage : m)));
500
599
  } finally {
501
600
  setIsLoading(false);
@@ -508,6 +607,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
508
607
  }
509
608
 
510
609
  setIsGeneratingSample(true);
610
+
511
611
  try {
512
612
  const url = `${baseUrl}/_agentuity/workbench/sample?agentId=${encodeURIComponent(agentId)}`;
513
613
  const headers: HeadersInit = {
@@ -515,8 +615,9 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
515
615
  };
516
616
 
517
617
  if (apiKey) {
518
- headers['Authorization'] = `Bearer ${apiKey}`;
618
+ headers.Authorization = `Bearer ${apiKey}`;
519
619
  }
620
+
520
621
  // Keep thread id stable across workbench endpoints.
521
622
  if (typeof headers === 'object' && headers && !Array.isArray(headers)) {
522
623
  applyThreadIdHeader(headers as Record<string, string>);
@@ -527,23 +628,29 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
527
628
  headers,
528
629
  credentials: 'include',
529
630
  });
631
+
530
632
  persistThreadIdFromResponse(response);
531
633
 
532
634
  if (!response.ok) {
533
635
  let errorMessage = `Request failed with status ${response.status}`;
636
+
534
637
  try {
535
638
  const errorData = await response.json();
639
+
536
640
  errorMessage = errorData.error || errorData.message || errorMessage;
537
641
  } catch {
538
642
  errorMessage = response.statusText || errorMessage;
539
643
  }
644
+
540
645
  throw new Error(errorMessage);
541
646
  }
542
647
 
543
648
  const sample = await response.json();
649
+
544
650
  return JSON.stringify(sample, null, 2);
545
651
  } catch (error) {
546
652
  logger.error('Failed to generate sample JSON:', error);
653
+
547
654
  throw error;
548
655
  } finally {
549
656
  setIsGeneratingSample(false);
@@ -552,6 +659,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
552
659
 
553
660
  const handleAgentSelect = async (agentId: string) => {
554
661
  logger.debug('🔄 handleAgentSelect called with:', agentId);
662
+
555
663
  setSelectedAgent(agentId);
556
664
  // Save selection to localStorage for persistence across sessions
557
665
  saveSelectedAgent(agentId);
@@ -567,9 +675,11 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
567
675
 
568
676
  try {
569
677
  const headers: Record<string, string> = {};
678
+
570
679
  if (apiKey) {
571
680
  headers.Authorization = `Bearer ${apiKey}`;
572
681
  }
682
+
573
683
  applyThreadIdHeader(headers);
574
684
 
575
685
  const url = `${baseUrl}/_agentuity/workbench/state?agentId=${encodeURIComponent(agentId)}`;
@@ -578,10 +688,12 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
578
688
  headers,
579
689
  credentials: 'include',
580
690
  });
691
+
581
692
  persistThreadIdFromResponse(response);
582
693
 
583
694
  if (response.ok) {
584
695
  setMessages([]);
696
+
585
697
  logger.debug('✅ Cleared state for agent:', agentId);
586
698
  } else {
587
699
  logger.debug('⚠️ Failed to clear state');
@@ -594,29 +706,25 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
594
706
  );
595
707
 
596
708
  const contextValue: WorkbenchContextType = {
597
- config,
598
709
  agents: agents || {},
599
- suggestions,
600
- messages,
601
- setMessages,
602
- selectedAgent,
603
- setSelectedAgent: handleAgentSelect,
604
- inputMode,
605
- setInputMode,
606
- isLoading: isLoading || !!schemasLoading,
607
- submitMessage,
710
+ clearAgentState,
711
+ config,
712
+ connectionStatus,
713
+ env,
608
714
  generateSample,
715
+ inputMode,
609
716
  isGeneratingSample,
610
- isAuthenticated,
611
- // Schema data from API
717
+ isLoading: isLoading || !!schemasLoading,
718
+ messages,
719
+ refetchSchemas,
612
720
  schemas: schemaData,
613
- schemasLoading: !!schemasLoading,
614
721
  schemasError,
615
- refetchSchemas,
616
- // Connection status
617
- connectionStatus,
618
- // Clear agent state
619
- clearAgentState,
722
+ schemasLoading: !!schemasLoading,
723
+ selectedAgent,
724
+ setInputMode,
725
+ setMessages,
726
+ setSelectedAgent: handleAgentSelect,
727
+ submitMessage,
620
728
  };
621
729
 
622
730
  return <WorkbenchContext.Provider value={contextValue}>{children}</WorkbenchContext.Provider>;
@@ -1,5 +1,5 @@
1
- import * as React from 'react';
2
1
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
2
+ import type * as React from 'react';
3
3
 
4
4
  import { cn } from '../../lib/utils';
5
5
 
@@ -1,6 +1,6 @@
1
- import * as React from 'react';
2
1
  import { Command as CommandPrimitive } from 'cmdk';
3
2
  import { SearchIcon } from 'lucide-react';
3
+ import type * as React from 'react';
4
4
 
5
5
  import { cn } from '../../lib/utils';
6
6
  import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from './dialog';
@@ -1,6 +1,6 @@
1
- import * as React from 'react';
2
1
  import * as DialogPrimitive from '@radix-ui/react-dialog';
3
2
  import { XIcon } from 'lucide-react';
3
+ import type * as React from 'react';
4
4
 
5
5
  import { cn } from '../../lib/utils';
6
6
 
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
- import * as React from 'react';
4
3
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
5
4
  import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react';
5
+ import type * as React from 'react';
6
6
 
7
7
  import { cn } from '../../lib/utils';
8
8
 
@@ -1,5 +1,5 @@
1
- import * as React from 'react';
2
1
  import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
2
+ import type * as React from 'react';
3
3
 
4
4
  import { cn } from '../../lib/utils';
5
5
 
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
- import * as React from 'react';
4
3
  import { cva, type VariantProps } from 'class-variance-authority';
4
+ import type * as React from 'react';
5
5
 
6
6
  import { cn } from '../../lib/utils';
7
7
  import { Button } from './button';
@@ -1,4 +1,4 @@
1
- import * as React from 'react';
1
+ import type * as React from 'react';
2
2
 
3
3
  import { cn } from '../../lib/utils';
4
4
 
@@ -1,5 +1,5 @@
1
- import * as React from 'react';
2
1
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
2
+ import type * as React from 'react';
3
3
 
4
4
  import { cn } from '../../lib/utils';
5
5
 
@@ -1,4 +1,4 @@
1
- import * as React from 'react';
1
+ import type * as React from 'react';
2
2
 
3
3
  import { cn } from '../../lib/utils';
4
4
 
@@ -23,7 +23,7 @@ const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
23
23
  export function ThemeProvider({
24
24
  children,
25
25
  defaultTheme = 'system',
26
- storageKey = 'workbench-ui-theme',
26
+ storageKey = 'agentuity-workbench-ui-theme',
27
27
  ...props
28
28
  }: ThemeProviderProps) {
29
29
  const [theme, setTheme] = useState<Theme>(
@@ -1,5 +1,5 @@
1
- import * as React from 'react';
2
1
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
2
+ import type * as React from 'react';
3
3
 
4
4
  import { cn } from '../../lib/utils';
5
5