@agentuity/workbench 0.0.105 → 0.0.107

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 (171) 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/input-section.js +162 -0
  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} +2 -2
  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} +87 -60
  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 +9 -7
  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 +360 -295
  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 +326 -0
  123. package/src/components/internal/{Header.tsx → header.tsx} +37 -40
  124. package/src/components/internal/{InputSection.tsx → input-section.tsx} +173 -119
  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 +96 -0
  128. package/src/components/internal/{WorkbenchProvider.tsx → workbench-provider.tsx} +194 -68
  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 +26 -15
  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 +0 -152
  156. package/dist/components/internal/InputSection.js.map +0 -1
  157. package/dist/components/internal/MonacoJsonEditor.d.ts +0 -13
  158. package/dist/components/internal/MonacoJsonEditor.d.ts.map +0 -1
  159. package/dist/components/internal/MonacoJsonEditor.js.map +0 -1
  160. package/dist/components/internal/Schema.d.ts.map +0 -1
  161. package/dist/components/internal/Schema.js +0 -13
  162. package/dist/components/internal/Schema.js.map +0 -1
  163. package/dist/components/internal/WorkbenchProvider.d.ts.map +0 -1
  164. package/dist/components/internal/WorkbenchProvider.js.map +0 -1
  165. package/dist/components/ui/resizable-provider.d.ts.map +0 -1
  166. package/dist/components/ui/resizable-provider.js.map +0 -1
  167. package/src/components/internal/Chat.tsx +0 -201
  168. package/src/components/internal/Schema.tsx +0 -100
  169. /package/dist/components/{ui → internal}/resizable-provider.d.ts +0 -0
  170. /package/dist/components/{ui → internal}/resizable-provider.js +0 -0
  171. /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,25 +25,38 @@ 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
46
 
32
47
  // localStorage utilities scoped by project
33
48
  const getStorageKey = useCallback(
34
- (key: string) => `agentuity_workbench_${config.projectId}_${key}`,
49
+ (key: string) =>
50
+ `agentuity-workbench-${config.projectId ? `${config.projectId}-` : ''}${key}`,
35
51
  [config.projectId]
36
52
  );
37
53
 
38
54
  const saveSelectedAgent = useCallback(
39
55
  (agentId: string) => {
40
56
  try {
41
- localStorage.setItem(getStorageKey('selected_agent'), agentId);
57
+ localStorage.setItem(getStorageKey('selected-agent'), agentId);
42
58
  } catch (error) {
43
- console.warn('Failed to save selected agent to localStorage:', error);
59
+ logger.warn('Failed to save selected agent to localStorage:', error);
44
60
  }
45
61
  },
46
62
  [getStorageKey]
@@ -48,9 +64,9 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
48
64
 
49
65
  const loadSelectedAgent = useCallback((): string | null => {
50
66
  try {
51
- return localStorage.getItem(getStorageKey('selected_agent'));
67
+ return localStorage.getItem(getStorageKey('selected-agent'));
52
68
  } catch (error) {
53
- console.warn('Failed to load selected agent from localStorage:', error);
69
+ logger.warn('Failed to load selected agent from localStorage:', error);
54
70
  return null;
55
71
  }
56
72
  }, [getStorageKey]);
@@ -58,9 +74,9 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
58
74
  const saveThreadId = useCallback(
59
75
  (threadId: string) => {
60
76
  try {
61
- localStorage.setItem(getStorageKey('thread_id'), threadId);
77
+ localStorage.setItem(getStorageKey('thread-id'), threadId);
62
78
  } catch (error) {
63
- console.warn('Failed to save thread id to localStorage:', error);
79
+ logger.warn('Failed to save thread id to localStorage:', error);
64
80
  }
65
81
  },
66
82
  [getStorageKey]
@@ -68,9 +84,10 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
68
84
 
69
85
  const loadThreadId = useCallback((): string | null => {
70
86
  try {
71
- return localStorage.getItem(getStorageKey('thread_id'));
87
+ return localStorage.getItem(getStorageKey('thread-id'));
72
88
  } catch (error) {
73
- console.warn('Failed to load thread id from localStorage:', error);
89
+ logger.warn('Failed to load thread id from localStorage:', error);
90
+
74
91
  return null;
75
92
  }
76
93
  }, [getStorageKey]);
@@ -120,6 +137,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
120
137
  useEffect(() => {
121
138
  if (isBaseUrlNull) {
122
139
  logger.debug('🔌 Setting connection status to disconnected (baseUrl is null)');
140
+
123
141
  setConnectionStatus('disconnected');
124
142
  }
125
143
  }, [isBaseUrlNull, logger]);
@@ -143,6 +161,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
143
161
 
144
162
  // WebSocket connection for dev server restart detection
145
163
  const wsBaseUrl = isBaseUrlNull ? undefined : baseUrl;
164
+
146
165
  useEffect(() => {
147
166
  if (isBaseUrlNull) {
148
167
  logger.debug('🔌 WebSocket connection disabled (baseUrl is null)');
@@ -178,18 +197,17 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
178
197
 
179
198
  // Convert schema data to Agent format, no fallback
180
199
  const agents = schemaData?.agents;
200
+
181
201
  // Log schema fetch errors for debugging
182
202
  useEffect(() => {
183
203
  if (schemasError) {
184
- console.warn(
204
+ logger.warn(
185
205
  'Failed to fetch agent schemas from API, using static configuration:',
186
206
  schemasError.message
187
207
  );
188
208
  }
189
209
  }, [schemasError]);
190
210
 
191
- const [suggestions, _setSuggestions] = useState<string[]>([]);
192
-
193
211
  // Fetch state for an agent
194
212
  const fetchAgentState = useCallback(
195
213
  async (agentId: string) => {
@@ -205,18 +223,23 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
205
223
 
206
224
  try {
207
225
  const headers: Record<string, string> = {};
226
+
208
227
  if (apiKey) {
209
228
  headers.Authorization = `Bearer ${apiKey}`;
210
229
  }
230
+
211
231
  applyThreadIdHeader(headers);
212
232
 
213
233
  const url = `${baseUrl}/_agentuity/workbench/state?agentId=${encodeURIComponent(agentId)}`;
234
+
214
235
  logger.debug('📡 Fetching state for agent:', agentId);
236
+
215
237
  const response = await fetch(url, {
216
238
  method: 'GET',
217
239
  headers,
218
240
  credentials: 'include',
219
241
  });
242
+
220
243
  persistThreadIdFromResponse(response);
221
244
 
222
245
  if (response.ok) {
@@ -233,8 +256,10 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
233
256
  typeof msg.data === 'object'
234
257
  ? JSON.stringify(msg.data, null, 2)
235
258
  : String(msg.data);
259
+
236
260
  // Use stable ID based on index and a hash of content to maintain identity
237
261
  const contentHash = text.substring(0, 20).replace(/[^a-zA-Z0-9]/g, '');
262
+
238
263
  return {
239
264
  id: `state_${agentId}_${index}_${contentHash}`,
240
265
  role: msg.type === 'input' ? 'user' : 'assistant',
@@ -243,13 +268,16 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
243
268
  });
244
269
 
245
270
  setMessages(uiMessages);
271
+
246
272
  logger.debug('✅ Loaded state messages:', uiMessages.length);
247
273
  } else {
248
274
  logger.debug('⚠️ Failed to fetch state, starting with empty messages');
275
+
249
276
  setMessages([]);
250
277
  }
251
278
  } catch (error) {
252
279
  logger.debug('⚠️ Error fetching state:', error);
280
+
253
281
  setMessages([]);
254
282
  }
255
283
  },
@@ -264,16 +292,20 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
264
292
  // First, check for agent query parameter in URL
265
293
  const urlParams = new URLSearchParams(window.location.search);
266
294
  const agentFromUrl = urlParams.get('agent');
295
+
267
296
  logger.debug('🔗 Agent from URL query param:', agentFromUrl);
268
297
 
269
298
  // Try to find agent by URL param (matches agentId only)
270
299
  let agentToSelect: string | null = null;
300
+
271
301
  if (agentFromUrl) {
272
302
  const matchedAgent = Object.values(agents).find(
273
303
  (agent) => agent.metadata.agentId === agentFromUrl
274
304
  );
305
+
275
306
  if (matchedAgent) {
276
307
  logger.debug('✅ Found agent from URL param:', matchedAgent.metadata.name);
308
+
277
309
  agentToSelect = matchedAgent.metadata.agentId;
278
310
  }
279
311
  }
@@ -281,6 +313,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
281
313
  // If no URL param match, try localStorage
282
314
  if (!agentToSelect) {
283
315
  const savedAgentId = loadSelectedAgent();
316
+
284
317
  logger.debug('💾 Saved agent from localStorage:', savedAgentId);
285
318
 
286
319
  const savedAgent = savedAgentId
@@ -289,6 +322,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
289
322
 
290
323
  if (savedAgent && savedAgentId) {
291
324
  logger.debug('✅ Restoring saved agent:', savedAgent.metadata.name);
325
+
292
326
  agentToSelect = savedAgentId;
293
327
  }
294
328
  }
@@ -298,44 +332,44 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
298
332
  const sortedAgents = Object.values(agents).sort((a, b) =>
299
333
  a.metadata.name.localeCompare(b.metadata.name)
300
334
  );
335
+
301
336
  const firstAgent = sortedAgents[0];
337
+
302
338
  logger.debug(
303
339
  '🎯 No saved agent found, using first agent (alphabetically):',
304
340
  firstAgent
305
341
  );
342
+
306
343
  agentToSelect = firstAgent.metadata.agentId;
307
344
  }
308
345
 
309
346
  logger.debug('🆔 Setting selectedAgent to:', agentToSelect);
347
+
310
348
  setSelectedAgent(agentToSelect);
311
349
  saveSelectedAgent(agentToSelect);
312
350
  fetchAgentState(agentToSelect);
313
351
  }
314
352
  }, [agents, selectedAgent, loadSelectedAgent, saveSelectedAgent, logger, fetchAgentState]);
315
353
 
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
354
  const submitMessage = async (value: string, _mode: 'text' | 'form' = 'text') => {
326
355
  if (!selectedAgent) return;
327
356
 
328
357
  logger.debug('🚀 Submitting message with selectedAgent:', selectedAgent);
358
+
329
359
  const selectedAgentData = agents
330
360
  ? Object.values(agents).find((agent) => agent.metadata.agentId === selectedAgent)
331
361
  : undefined;
362
+
332
363
  logger.debug('📊 Found selectedAgentData:', selectedAgentData);
364
+
333
365
  const hasInputSchema = selectedAgentData?.schema?.input?.json;
366
+
334
367
  logger.debug('📝 hasInputSchema:', hasInputSchema, 'value:', value);
335
368
 
336
369
  // Only require value for agents with input schemas
337
370
  if (hasInputSchema && !value.trim()) {
338
371
  logger.debug('❌ Returning early - hasInputSchema but no value');
372
+
339
373
  return;
340
374
  }
341
375
 
@@ -353,7 +387,6 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
353
387
  role: 'user',
354
388
  parts: [{ type: 'text', text: displayText }],
355
389
  };
356
-
357
390
  const assistantMessageId = (now + 1).toString();
358
391
  const placeholderAssistantMessage: UIMessage = {
359
392
  id: assistantMessageId,
@@ -365,8 +398,10 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
365
398
  setIsLoading(true);
366
399
 
367
400
  logger.debug('🔗 baseUrl:', baseUrl, 'isBaseUrlNull:', isBaseUrlNull);
401
+
368
402
  if (!baseUrl || isBaseUrlNull) {
369
403
  logger.debug('❌ Message submission blocked - baseUrl is null or missing');
404
+
370
405
  const errorMessage: UIMessage = {
371
406
  id: assistantMessageId,
372
407
  role: 'assistant',
@@ -377,8 +412,11 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
377
412
  },
378
413
  ],
379
414
  };
415
+
380
416
  setMessages((prev) => prev.map((m) => (m.id === assistantMessageId ? errorMessage : m)));
417
+
381
418
  setIsLoading(false);
419
+
382
420
  return;
383
421
  }
384
422
 
@@ -386,6 +424,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
386
424
  // Parse input - if it's JSON, parse it, otherwise use as string
387
425
  // For agents without input schema, send undefined
388
426
  let parsedInput: unknown;
427
+
389
428
  if (!hasInputSchema) {
390
429
  parsedInput = undefined;
391
430
  } else {
@@ -397,17 +436,17 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
397
436
  }
398
437
 
399
438
  logger.debug('🌐 About to make API call...');
439
+
400
440
  // Call execution endpoint with timeout
401
441
  const headers: Record<string, string> = {
402
442
  'Content-Type': 'application/json',
403
443
  };
444
+
404
445
  if (apiKey) {
405
446
  headers.Authorization = `Bearer ${apiKey}`;
406
447
  }
407
- applyThreadIdHeader(headers);
408
448
 
409
- const controller = new AbortController();
410
- const timeoutId = setTimeout(() => controller.abort(), 30000); // 30s timeout
449
+ applyThreadIdHeader(headers);
411
450
 
412
451
  const startTime = performance.now();
413
452
 
@@ -416,32 +455,55 @@ 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,
423
464
  body: JSON.stringify(requestPayload),
424
- signal: controller.signal,
425
465
  credentials: 'include',
426
466
  });
467
+
427
468
  persistThreadIdFromResponse(response);
428
- clearTimeout(timeoutId);
429
469
 
430
470
  if (!response.ok) {
431
- let errorMessage = `Request failed with status ${response.status}`;
471
+ let errorText = `Request failed with status ${response.status}`;
472
+
432
473
  try {
433
474
  const errorData = await response.json();
434
- errorMessage = errorData.error || errorData.message || errorMessage;
475
+
476
+ errorText = errorData.error || errorData.message || errorText;
435
477
  } catch {
436
478
  // If JSON parsing fails, use status text
437
- errorMessage = response.statusText || errorMessage;
479
+ errorText = response.statusText || errorText;
438
480
  }
439
- throw new Error(errorMessage);
481
+
482
+ const errorPayload = JSON.stringify({
483
+ __agentError: true,
484
+ message: errorText,
485
+ code: `HTTP_${response.status}`,
486
+ });
487
+
488
+ const errorMessage: UIMessage = {
489
+ id: assistantMessageId,
490
+ role: 'assistant',
491
+ parts: [{ type: 'text', text: errorPayload }],
492
+ };
493
+
494
+ setMessages((prev) =>
495
+ prev.map((m) => (m.id === assistantMessageId ? errorMessage : m))
496
+ );
497
+
498
+ setIsLoading(false);
499
+
500
+ return;
440
501
  }
441
502
 
442
- let result;
503
+ let responseBody: unknown;
504
+
443
505
  try {
444
- result = await response.json();
506
+ responseBody = await response.json();
445
507
  } catch (jsonError) {
446
508
  throw new Error(`Invalid JSON response from server: ${jsonError}`);
447
509
  }
@@ -458,27 +520,79 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
458
520
  const tokensRecord = tokensHeader ? parseTokensHeader(tokensHeader) : undefined;
459
521
  const totalTokens = tokensRecord ? getTotalTokens(tokensRecord) : undefined;
460
522
 
523
+ // Handle wrapped response shape: { success, data?, error? }
524
+ const envelope =
525
+ typeof responseBody === 'object' && responseBody !== null
526
+ ? (responseBody as {
527
+ success?: boolean;
528
+ data?: unknown;
529
+ error?: {
530
+ message?: string;
531
+ stack?: string;
532
+ code?: string;
533
+ cause?: unknown;
534
+ };
535
+ })
536
+ : null;
537
+
538
+ if (envelope && 'success' in envelope && envelope.success === false && envelope.error) {
539
+ // Agent execution error - encode as special JSON format for ErrorBubble
540
+ const errorPayload = JSON.stringify({
541
+ __agentError: true,
542
+ message: envelope.error.message || 'Unknown error',
543
+ stack: envelope.error.stack,
544
+ code: envelope.error.code,
545
+ cause: envelope.error.cause,
546
+ });
547
+
548
+ const errorMessage: UIMessage = {
549
+ id: assistantMessageId,
550
+ role: 'assistant',
551
+ parts: [{ type: 'text', text: errorPayload }],
552
+ };
553
+
554
+ setMessages((prev) =>
555
+ prev.map((m) => (m.id === assistantMessageId ? errorMessage : m))
556
+ );
557
+ return;
558
+ }
559
+
560
+ // Success - extract data from envelope (or use raw response if not wrapped)
561
+ const result =
562
+ envelope && 'success' in envelope && envelope.success === true
563
+ ? envelope.data
564
+ : responseBody;
565
+
461
566
  // Format result as JSON string for display
462
567
  const resultText =
463
568
  typeof result === 'object' ? JSON.stringify(result, null, 2) : String(result);
464
569
 
465
- const assistantMessage: UIMessage & { tokens?: string; duration?: string } = {
570
+ const sessionId = response.headers.get('x-session-id') || undefined;
571
+
572
+ const assistantMessage: UIMessage & {
573
+ tokens?: string;
574
+ duration?: string;
575
+ sessionId?: string;
576
+ } = {
466
577
  id: assistantMessageId,
467
578
  role: 'assistant',
468
579
  parts: [{ type: 'text', text: resultText }],
469
580
  tokens: totalTokens?.toString(),
470
581
  duration,
582
+ sessionId,
471
583
  };
472
584
 
473
585
  setMessages((prev) =>
474
586
  prev.map((m) => (m.id === assistantMessageId ? assistantMessage : m))
475
587
  );
476
588
  } catch (fetchError) {
477
- clearTimeout(timeoutId);
589
+ logger.error('❌ Failed to submit message:', fetchError);
590
+
478
591
  throw fetchError;
479
592
  }
480
593
  } catch (error) {
481
- console.error('Failed to submit message:', error);
594
+ logger.error('Failed to submit message:', error);
595
+
482
596
  const errorText =
483
597
  error instanceof Error
484
598
  ? error.name === 'AbortError'
@@ -486,16 +600,19 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
486
600
  : error.message
487
601
  : 'Sorry, I encountered an error processing your message.';
488
602
 
603
+ const errorPayload = JSON.stringify({
604
+ __agentError: true,
605
+ message: errorText,
606
+ code:
607
+ error instanceof Error && error.name === 'AbortError' ? 'TIMEOUT' : 'REQUEST_ERROR',
608
+ });
609
+
489
610
  const errorMessage: UIMessage = {
490
611
  id: assistantMessageId,
491
612
  role: 'assistant',
492
- parts: [
493
- {
494
- type: 'text',
495
- text: errorText,
496
- },
497
- ],
613
+ parts: [{ type: 'text', text: errorPayload }],
498
614
  };
615
+
499
616
  setMessages((prev) => prev.map((m) => (m.id === assistantMessageId ? errorMessage : m)));
500
617
  } finally {
501
618
  setIsLoading(false);
@@ -508,6 +625,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
508
625
  }
509
626
 
510
627
  setIsGeneratingSample(true);
628
+
511
629
  try {
512
630
  const url = `${baseUrl}/_agentuity/workbench/sample?agentId=${encodeURIComponent(agentId)}`;
513
631
  const headers: HeadersInit = {
@@ -515,8 +633,9 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
515
633
  };
516
634
 
517
635
  if (apiKey) {
518
- headers['Authorization'] = `Bearer ${apiKey}`;
636
+ headers.Authorization = `Bearer ${apiKey}`;
519
637
  }
638
+
520
639
  // Keep thread id stable across workbench endpoints.
521
640
  if (typeof headers === 'object' && headers && !Array.isArray(headers)) {
522
641
  applyThreadIdHeader(headers as Record<string, string>);
@@ -527,23 +646,29 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
527
646
  headers,
528
647
  credentials: 'include',
529
648
  });
649
+
530
650
  persistThreadIdFromResponse(response);
531
651
 
532
652
  if (!response.ok) {
533
653
  let errorMessage = `Request failed with status ${response.status}`;
654
+
534
655
  try {
535
656
  const errorData = await response.json();
657
+
536
658
  errorMessage = errorData.error || errorData.message || errorMessage;
537
659
  } catch {
538
660
  errorMessage = response.statusText || errorMessage;
539
661
  }
662
+
540
663
  throw new Error(errorMessage);
541
664
  }
542
665
 
543
666
  const sample = await response.json();
667
+
544
668
  return JSON.stringify(sample, null, 2);
545
669
  } catch (error) {
546
670
  logger.error('Failed to generate sample JSON:', error);
671
+
547
672
  throw error;
548
673
  } finally {
549
674
  setIsGeneratingSample(false);
@@ -552,6 +677,7 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
552
677
 
553
678
  const handleAgentSelect = async (agentId: string) => {
554
679
  logger.debug('🔄 handleAgentSelect called with:', agentId);
680
+
555
681
  setSelectedAgent(agentId);
556
682
  // Save selection to localStorage for persistence across sessions
557
683
  saveSelectedAgent(agentId);
@@ -567,9 +693,11 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
567
693
 
568
694
  try {
569
695
  const headers: Record<string, string> = {};
696
+
570
697
  if (apiKey) {
571
698
  headers.Authorization = `Bearer ${apiKey}`;
572
699
  }
700
+
573
701
  applyThreadIdHeader(headers);
574
702
 
575
703
  const url = `${baseUrl}/_agentuity/workbench/state?agentId=${encodeURIComponent(agentId)}`;
@@ -578,10 +706,12 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
578
706
  headers,
579
707
  credentials: 'include',
580
708
  });
709
+
581
710
  persistThreadIdFromResponse(response);
582
711
 
583
712
  if (response.ok) {
584
713
  setMessages([]);
714
+
585
715
  logger.debug('✅ Cleared state for agent:', agentId);
586
716
  } else {
587
717
  logger.debug('⚠️ Failed to clear state');
@@ -594,29 +724,25 @@ export function WorkbenchProvider({ config, isAuthenticated, children }: Workben
594
724
  );
595
725
 
596
726
  const contextValue: WorkbenchContextType = {
597
- config,
598
727
  agents: agents || {},
599
- suggestions,
600
- messages,
601
- setMessages,
602
- selectedAgent,
603
- setSelectedAgent: handleAgentSelect,
604
- inputMode,
605
- setInputMode,
606
- isLoading: isLoading || !!schemasLoading,
607
- submitMessage,
728
+ clearAgentState,
729
+ config,
730
+ connectionStatus,
731
+ env,
608
732
  generateSample,
733
+ inputMode,
609
734
  isGeneratingSample,
610
- isAuthenticated,
611
- // Schema data from API
735
+ isLoading: isLoading || !!schemasLoading,
736
+ messages,
737
+ refetchSchemas,
612
738
  schemas: schemaData,
613
- schemasLoading: !!schemasLoading,
614
739
  schemasError,
615
- refetchSchemas,
616
- // Connection status
617
- connectionStatus,
618
- // Clear agent state
619
- clearAgentState,
740
+ schemasLoading: !!schemasLoading,
741
+ selectedAgent,
742
+ setInputMode,
743
+ setMessages,
744
+ setSelectedAgent: handleAgentSelect,
745
+ submitMessage,
620
746
  };
621
747
 
622
748
  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