@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,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
 
@@ -1,5 +1,6 @@
1
- import { JSONSchema7 } from 'ai';
2
- import { useState, useEffect, useCallback } from 'react';
1
+ import type { JSONSchema7 } from 'ai';
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import { useLogger } from './useLogger';
3
4
 
4
5
  export interface AgentSchema {
5
6
  input?: {
@@ -13,18 +14,18 @@ export interface AgentSchema {
13
14
  }
14
15
 
15
16
  export interface AgentMetadata {
16
- id: string;
17
- name: string;
17
+ agentId: string;
18
18
  description?: string;
19
- version?: string;
20
19
  filename?: string;
20
+ id: string;
21
21
  identifier?: string;
22
- agentId: string;
22
+ name: string;
23
+ version?: string;
23
24
  }
24
25
 
25
26
  export interface AgentSchemaData {
26
- schema: AgentSchema;
27
27
  metadata: AgentMetadata;
28
+ schema: AgentSchema;
28
29
  }
29
30
 
30
31
  export interface AgentSchemasResponse {
@@ -32,15 +33,15 @@ export interface AgentSchemasResponse {
32
33
  }
33
34
 
34
35
  export interface UseAgentSchemasOptions {
35
- baseUrl?: string;
36
36
  apiKey?: string;
37
+ baseUrl?: string;
37
38
  enabled?: boolean;
38
39
  }
39
40
 
40
41
  export interface UseAgentSchemasResult {
41
42
  data: AgentSchemasResponse | null;
42
- isLoading: boolean;
43
43
  error: Error | null;
44
+ isLoading: boolean;
44
45
  refetch: () => void;
45
46
  }
46
47
 
@@ -67,6 +68,7 @@ export interface UseAgentSchemasResult {
67
68
  export function useAgentSchemas(options: UseAgentSchemasOptions = {}): UseAgentSchemasResult {
68
69
  const { baseUrl = '', apiKey, enabled = true } = options;
69
70
 
71
+ const logger = useLogger('useAgentSchemas');
70
72
  const [data, setData] = useState<AgentSchemasResponse | null>(null);
71
73
  const [isLoading, setIsLoading] = useState(false);
72
74
  const [error, setError] = useState<Error | null>(null);
@@ -84,7 +86,7 @@ export function useAgentSchemas(options: UseAgentSchemasOptions = {}): UseAgentS
84
86
  };
85
87
 
86
88
  if (apiKey) {
87
- headers['Authorization'] = `Bearer ${apiKey}`;
89
+ headers.Authorization = `Bearer ${apiKey}`;
88
90
  }
89
91
 
90
92
  const response = await fetch(url, {
@@ -96,27 +98,36 @@ export function useAgentSchemas(options: UseAgentSchemasOptions = {}): UseAgentS
96
98
  // Handle 404/500 gracefully without throwing
97
99
  if (response.status === 401) {
98
100
  setError(new Error('Unauthorized: Invalid or missing API key'));
101
+
99
102
  return;
100
103
  }
104
+
101
105
  if (response.status === 404 || response.status >= 500) {
102
106
  setError(new Error(`Server error: ${response.status} ${response.statusText}`));
107
+
103
108
  return;
104
109
  }
110
+
105
111
  setError(new Error(`HTTP ${response.status}: ${response.statusText}`));
112
+
106
113
  return;
107
114
  }
108
115
 
109
116
  try {
110
117
  const result = (await response.json()) as AgentSchemasResponse;
118
+
111
119
  setData(result);
112
120
  } catch (jsonError) {
113
121
  setError(new Error('Invalid JSON response from server'));
114
- console.error('Failed to parse JSON response:', jsonError);
122
+
123
+ logger.error('Failed to parse JSON response:', jsonError);
115
124
  }
116
125
  } catch (err) {
117
126
  const error = err instanceof Error ? err : new Error('Unknown error occurred');
127
+
118
128
  setError(error);
119
- console.error('Failed to fetch agent schemas:', error);
129
+
130
+ logger.error('Failed to fetch agent schemas:', error);
120
131
  } finally {
121
132
  setIsLoading(false);
122
133
  }
@@ -132,8 +143,8 @@ export function useAgentSchemas(options: UseAgentSchemasOptions = {}): UseAgentS
132
143
 
133
144
  return {
134
145
  data,
135
- isLoading,
136
146
  error,
147
+ isLoading,
137
148
  refetch,
138
149
  };
139
150
  }
@@ -148,10 +159,10 @@ export function useAgentSchema(agentName: string, options: UseAgentSchemasOption
148
159
 
149
160
  return {
150
161
  data: agentData,
151
- isLoading,
152
162
  error,
163
+ isLoading,
164
+ metadata: agentData?.metadata || null,
153
165
  refetch,
154
166
  schema: agentData?.schema || null,
155
- metadata: agentData?.metadata || null,
156
167
  };
157
168
  }
@@ -12,9 +12,11 @@ interface Logger {
12
12
  const getLogLevel = (): LogLevel | null => {
13
13
  try {
14
14
  const level = localStorage.getItem('AGENTUITY_LOG_LEVEL');
15
+
15
16
  if (level && ['debug', 'info', 'warn', 'error'].includes(level)) {
16
17
  return level as LogLevel;
17
18
  }
19
+
18
20
  return null;
19
21
  } catch {
20
22
  return null;
@@ -23,6 +25,7 @@ const getLogLevel = (): LogLevel | null => {
23
25
 
24
26
  const shouldLog = (messageLevel: LogLevel): boolean => {
25
27
  const currentLevel = getLogLevel();
28
+
26
29
  if (!currentLevel) return false;
27
30
 
28
31
  const levels: Record<LogLevel, number> = {
@@ -39,10 +42,13 @@ export function useLogger(component?: string): Logger {
39
42
  const createLogFunction = useCallback(
40
43
  (level: LogLevel) =>
41
44
  (...args: unknown[]) => {
42
- if (!shouldLog(level)) return;
45
+ if (!shouldLog(level)) {
46
+ return;
47
+ }
43
48
 
44
49
  const prefix = component ? `[${component}]` : '[Workbench]';
45
50
  const consoleFn = console[level] || console.log;
51
+
46
52
  consoleFn(prefix, ...args);
47
53
  },
48
54
  [component]
@@ -1,22 +1,22 @@
1
1
  import { useCallback, useEffect, useRef, useState } from 'react';
2
2
 
3
3
  interface ReconnectOptions {
4
- onReconnect: () => void;
5
- threshold?: number;
6
4
  baseDelay?: number;
5
+ enabled?: () => boolean;
7
6
  factor?: number;
8
- maxDelay?: number;
9
7
  jitter?: number;
10
- enabled?: () => boolean;
8
+ maxDelay?: number;
9
+ onReconnect: () => void;
10
+ threshold?: number;
11
11
  }
12
12
 
13
13
  interface ReconnectManager {
14
- recordFailure: () => { scheduled: boolean; delay: number | null };
15
- recordSuccess: () => void;
16
14
  cancel: () => void;
17
- reset: () => void;
18
15
  dispose: () => void;
19
16
  getAttempts: () => number;
17
+ recordFailure: () => { scheduled: boolean; delay: number | null };
18
+ recordSuccess: () => void;
19
+ reset: () => void;
20
20
  }
21
21
 
22
22
  function createReconnectManager(opts: ReconnectOptions): ReconnectManager {
@@ -26,12 +26,14 @@ function createReconnectManager(opts: ReconnectOptions): ReconnectManager {
26
26
  const cancel = () => {
27
27
  if (timer) {
28
28
  clearTimeout(timer);
29
+
29
30
  timer = null;
30
31
  }
31
32
  };
32
33
 
33
34
  const reset = () => {
34
35
  attempts = 0;
36
+
35
37
  cancel();
36
38
  };
37
39
 
@@ -42,14 +44,17 @@ function createReconnectManager(opts: ReconnectOptions): ReconnectManager {
42
44
  const factor = opts.factor ?? 2;
43
45
  const max = opts.maxDelay ?? 30000;
44
46
  const jitterMax = opts.jitter ?? 250;
45
- const backoff = Math.min(base * Math.pow(factor, attemptAfterThreshold), max);
47
+ const backoff = Math.min(base * factor ** attemptAfterThreshold, max);
46
48
  const jitter = jitterMax > 0 ? Math.random() * jitterMax : 0;
49
+
47
50
  return backoff + jitter;
48
51
  };
49
52
 
50
53
  const recordFailure = () => {
51
54
  attempts += 1;
55
+
52
56
  const threshold = opts.threshold ?? 0;
57
+
53
58
  if (opts.enabled && !opts.enabled()) {
54
59
  return { scheduled: false, delay: null };
55
60
  }
@@ -57,13 +62,18 @@ function createReconnectManager(opts: ReconnectOptions): ReconnectManager {
57
62
  if (attempts - threshold >= 0) {
58
63
  const after = Math.max(0, attempts - threshold);
59
64
  const delay = computeDelay(after);
65
+
60
66
  cancel();
67
+
61
68
  timer = setTimeout(() => {
62
69
  if (opts.enabled && !opts.enabled()) return;
70
+
63
71
  opts.onReconnect();
64
72
  }, delay);
73
+
65
74
  return { scheduled: true, delay };
66
75
  }
76
+
67
77
  return { scheduled: false, delay: null };
68
78
  };
69
79
 
@@ -75,12 +85,12 @@ function createReconnectManager(opts: ReconnectOptions): ReconnectManager {
75
85
  }
76
86
 
77
87
  export interface UseWorkbenchWebsocketOptions {
78
- baseUrl?: string;
79
88
  apiKey?: string;
89
+ baseUrl?: string;
80
90
  enabled?: boolean;
91
+ onAlive?: () => void;
81
92
  onConnect?: () => void;
82
93
  onReconnect?: () => void;
83
- onAlive?: () => void;
84
94
  onRestarting?: () => void;
85
95
  }
86
96
 
@@ -94,47 +104,59 @@ export function useWorkbenchWebsocket(
94
104
  ): UseWorkbenchWebsocketResult {
95
105
  const { baseUrl, apiKey, onConnect, onReconnect, onAlive, onRestarting } = options;
96
106
 
107
+ const [connected, setConnected] = useState(false);
108
+ const [error, setError] = useState<Error | null>(null);
109
+
110
+ const hasConnectedOnce = useRef(false);
97
111
  const manualClose = useRef(false);
98
- const wsRef = useRef<WebSocket | undefined>(undefined);
99
- const reconnectManagerRef = useRef<ReturnType<typeof createReconnectManager> | undefined>(
100
- undefined
101
- );
112
+ const onAliveRef = useRef(onAlive);
102
113
  const onConnectRef = useRef(onConnect);
103
114
  const onReconnectRef = useRef(onReconnect);
104
- const onAliveRef = useRef(onAlive);
105
115
  const onRestartingRef = useRef(onRestarting);
106
- const hasConnectedOnce = useRef(false);
107
-
108
- const [connected, setConnected] = useState(false);
109
- const [error, setError] = useState<Error | null>(null);
116
+ const reconnectManagerRef = useRef<ReturnType<typeof createReconnectManager> | undefined>(
117
+ undefined
118
+ );
119
+ const wsRef = useRef<WebSocket | undefined>(undefined);
110
120
 
111
121
  // Update refs when callbacks change
112
122
  useEffect(() => {
123
+ onAliveRef.current = onAlive;
113
124
  onConnectRef.current = onConnect;
114
125
  onReconnectRef.current = onReconnect;
115
- onAliveRef.current = onAlive;
116
126
  onRestartingRef.current = onRestarting;
117
127
  }, [onConnect, onReconnect, onAlive, onRestarting]);
118
128
 
119
129
  const wsUrl = useCallback(() => {
120
- if (!baseUrl) return null;
130
+ if (!baseUrl) {
131
+ return null;
132
+ }
133
+
121
134
  const wsBase = baseUrl.replace(/^http(s?):/, 'ws$1:');
122
135
  const url = new URL(`${wsBase}/_agentuity/workbench/ws`);
136
+
123
137
  if (apiKey) {
124
138
  url.searchParams.set('apiKey', apiKey);
125
139
  }
140
+
126
141
  return url.toString();
127
142
  }, [baseUrl, apiKey]);
128
143
 
129
144
  const connect = useCallback(() => {
130
- if (manualClose.current || !options.enabled) return;
145
+ if (manualClose.current || !options.enabled) {
146
+ return;
147
+ }
148
+
131
149
  const url = wsUrl();
132
- if (!url) return;
150
+
151
+ if (!url) {
152
+ return;
153
+ }
133
154
 
134
155
  wsRef.current = new WebSocket(url);
135
156
 
136
157
  wsRef.current.onopen = () => {
137
158
  reconnectManagerRef.current?.recordSuccess();
159
+
138
160
  setConnected(true);
139
161
  setError(null);
140
162
 
@@ -153,13 +175,17 @@ export function useWorkbenchWebsocket(
153
175
 
154
176
  wsRef.current.onclose = (evt) => {
155
177
  wsRef.current = undefined;
178
+
156
179
  setConnected(false);
180
+
157
181
  if (manualClose.current) {
158
182
  return;
159
183
  }
184
+
160
185
  if (evt.code !== 1000) {
161
186
  setError(new Error(`WebSocket closed: ${evt.code} ${evt.reason || ''}`));
162
187
  }
188
+
163
189
  reconnectManagerRef.current?.recordFailure();
164
190
  };
165
191
 
@@ -172,41 +198,50 @@ export function useWorkbenchWebsocket(
172
198
  onRestartingRef.current?.();
173
199
  }
174
200
  };
175
- }, [wsUrl]);
201
+ }, [wsUrl, options.enabled]);
176
202
 
177
203
  useEffect(() => {
178
204
  reconnectManagerRef.current = createReconnectManager({
179
- onReconnect: connect,
180
- threshold: 0,
181
205
  baseDelay: 500,
206
+ enabled: () => !manualClose.current && !!baseUrl,
182
207
  factor: 2,
183
- maxDelay: 30000,
184
208
  jitter: 500,
185
- enabled: () => !manualClose.current && !!baseUrl,
209
+ maxDelay: 30000,
210
+ onReconnect: connect,
211
+ threshold: 0,
186
212
  });
213
+
187
214
  return () => reconnectManagerRef.current?.dispose();
188
215
  }, [connect, baseUrl]);
189
216
 
190
217
  const cleanup = useCallback(() => {
191
218
  manualClose.current = true;
219
+
192
220
  reconnectManagerRef.current?.dispose();
221
+
193
222
  const ws = wsRef.current;
223
+
194
224
  if (ws) {
195
- ws.onopen = null;
196
- ws.onerror = null;
225
+ ws.close();
197
226
  ws.onclose = null;
227
+ ws.onerror = null;
198
228
  ws.onmessage = null;
199
- ws.close();
229
+ ws.onopen = null;
200
230
  }
231
+
201
232
  wsRef.current = undefined;
233
+
202
234
  setConnected(false);
203
235
  // Don't reset hasConnectedOnce here - we want to track if we've ever connected
204
236
  }, []);
205
237
 
206
238
  useEffect(() => {
207
- if (!baseUrl) return;
239
+ if (!baseUrl) {
240
+ return;
241
+ }
208
242
 
209
243
  manualClose.current = false;
244
+
210
245
  connect();
211
246
 
212
247
  return () => {
package/src/index.ts CHANGED
@@ -1,12 +1,8 @@
1
- // Export types
1
+ export { default as App } from './components/App';
2
+ export { Chat } from './components/internal/chat';
3
+ export { StatusIndicator } from './components/internal/header';
4
+ export { Schema } from './components/internal/schema';
5
+ export { useWorkbench, WorkbenchProvider } from './components/internal/workbench-provider';
2
6
  export type { WorkbenchInstance } from './types';
3
7
  export type { ConnectionStatus } from './types/config';
4
-
5
- // Export components
6
- export { default as App } from './components/App';
7
- export { Chat } from './components/internal/Chat';
8
- export { Schema } from './components/internal/Schema';
9
- export { StatusIndicator } from './components/internal/Header';
10
- export { WorkbenchProvider, useWorkbench } from './components/internal/WorkbenchProvider';
11
- // Export workbench functions
12
8
  export { createWorkbench } from './workbench';
package/src/lib/utils.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type ClassValue, clsx } from 'clsx';
2
2
  import { twMerge } from 'tailwind-merge';
3
+ import type { ErrorInfo } from '@/types/config';
3
4
 
4
5
  export function cn(...inputs: ClassValue[]) {
5
6
  return twMerge(clsx(inputs));
@@ -19,8 +20,10 @@ export function parseTokensHeader(header: string): Record<string, number> {
19
20
 
20
21
  for (const entry of entries) {
21
22
  const [model, countStr] = entry.split(':').map((s) => s.trim());
23
+
22
24
  if (model && countStr) {
23
25
  const count = Number.parseInt(countStr, 10);
26
+
24
27
  if (!Number.isNaN(count)) {
25
28
  result[model] = count;
26
29
  }
@@ -44,9 +47,11 @@ export const getProcessEnv = (key: string): string | undefined => {
44
47
  if (typeof import.meta.env !== 'undefined') {
45
48
  return import.meta.env[key];
46
49
  }
50
+
47
51
  if (typeof process !== 'undefined' && process.env) {
48
52
  return process.env[key];
49
53
  }
54
+
50
55
  return undefined;
51
56
  };
52
57
 
@@ -57,14 +62,19 @@ export const buildUrl = (
57
62
  query?: URLSearchParams
58
63
  ): string => {
59
64
  path = path.startsWith('/') ? path : `/${path}`;
65
+
60
66
  let url = base.replace(/\/$/, '') + path;
67
+
61
68
  if (subpath) {
62
69
  subpath = subpath.startsWith('/') ? subpath : `/${subpath}`;
70
+
63
71
  url += subpath;
64
72
  }
73
+
65
74
  if (query) {
66
75
  url += `?${query.toString()}`;
67
76
  }
77
+
68
78
  return url;
69
79
  };
70
80
 
@@ -80,3 +90,81 @@ export const defaultBaseUrl: string =
80
90
  getProcessEnv('AGENTUITY_URL') ||
81
91
  tryOrigin() ||
82
92
  'http://localhost:3500';
93
+
94
+ type SchemaLike = {
95
+ type?: string | string[];
96
+ properties?: Record<string, unknown>;
97
+ [key: string]: unknown;
98
+ };
99
+
100
+ function generateEmptyValueForSchema(schema: unknown): unknown {
101
+ if (typeof schema === 'boolean') {
102
+ return schema ? {} : undefined;
103
+ }
104
+
105
+ if (typeof schema !== 'object' || schema === null) {
106
+ return '';
107
+ }
108
+
109
+ const s = schema as SchemaLike;
110
+ const type = s.type;
111
+
112
+ if (Array.isArray(type)) {
113
+ return generateEmptyValueForSchema({ ...s, type: type[0] });
114
+ }
115
+
116
+ switch (type) {
117
+ case 'string':
118
+ return '';
119
+ case 'number':
120
+ case 'integer':
121
+ return 0;
122
+ case 'boolean':
123
+ return false;
124
+ case 'null':
125
+ return null;
126
+ case 'array':
127
+ return [];
128
+ case 'object': {
129
+ const result: Record<string, unknown> = {};
130
+
131
+ if (s.properties) {
132
+ for (const [key, propSchema] of Object.entries(s.properties)) {
133
+ result[key] = generateEmptyValueForSchema(propSchema);
134
+ }
135
+ }
136
+
137
+ return result;
138
+ }
139
+ default:
140
+ if (s.properties) {
141
+ const result: Record<string, unknown> = {};
142
+
143
+ for (const [key, propSchema] of Object.entries(s.properties)) {
144
+ result[key] = generateEmptyValueForSchema(propSchema);
145
+ }
146
+
147
+ return result;
148
+ }
149
+
150
+ return '';
151
+ }
152
+ }
153
+
154
+ export function generateTemplateFromSchema(schema?: unknown): string {
155
+ if (!schema) return '{}';
156
+
157
+ const template = generateEmptyValueForSchema(schema);
158
+
159
+ return JSON.stringify(template, null, 2);
160
+ }
161
+
162
+ export function formatErrorForCopy(error: ErrorInfo): string {
163
+ return [
164
+ error.code ? `[${error.code}] ${error.message}` : error.message,
165
+ error.stack,
166
+ error.cause ? `Cause: ${JSON.stringify(error.cause, null, 2)}` : null,
167
+ ]
168
+ .filter(Boolean)
169
+ .join('\n\n');
170
+ }
package/src/server.ts CHANGED
@@ -2,5 +2,5 @@
2
2
  // This file exports only the server-side createWorkbench function
3
3
  // without pulling in browser-side React components
4
4
 
5
- export { createWorkbench } from './workbench';
6
5
  export type { WorkbenchInstance } from './types';
6
+ export { createWorkbench } from './workbench';
@@ -1,39 +1,46 @@
1
- import type { UIMessage } from 'ai';
2
1
  import type { WorkbenchConfig } from '@agentuity/core/workbench';
2
+ import type { UIMessage } from 'ai';
3
3
  import type { AgentSchemaData, AgentSchemasResponse } from '../hooks/useAgentSchemas';
4
4
 
5
5
  export interface Agent {
6
+ avatar?: string;
7
+ description?: string;
6
8
  id: string;
7
9
  name: string;
8
- description?: string;
9
- avatar?: string;
10
10
  }
11
11
 
12
12
  export type ConnectionStatus = 'connected' | 'restarting' | 'disconnected';
13
13
 
14
14
  // Context type for the provider
15
15
  export interface WorkbenchContextType {
16
- config: WorkbenchConfig;
17
16
  agents: Record<string, AgentSchemaData>;
18
- suggestions: string[];
19
- messages: UIMessage[];
20
- setMessages: (messages: UIMessage[] | ((prev: UIMessage[]) => UIMessage[])) => void;
21
- selectedAgent: string;
22
- setSelectedAgent: (agentId: string) => void;
23
- inputMode: 'text' | 'form';
24
- setInputMode: (mode: 'text' | 'form') => void;
25
- isLoading: boolean;
26
- submitMessage: (value: string, mode?: 'text' | 'form') => Promise<void>;
17
+ clearAgentState: (agentId: string) => Promise<void>;
18
+ config: WorkbenchConfig;
19
+ connectionStatus: ConnectionStatus;
20
+ env: {
21
+ agentuity: boolean;
22
+ authenticated: boolean;
23
+ cloud: boolean;
24
+ };
27
25
  generateSample: (agentId: string) => Promise<string>;
26
+ inputMode: 'text' | 'form';
28
27
  isGeneratingSample: boolean;
29
- isAuthenticated: boolean;
30
- // Schema data from API
28
+ isLoading: boolean;
29
+ messages: UIMessage[];
30
+ refetchSchemas: () => void;
31
31
  schemas: AgentSchemasResponse | null;
32
- schemasLoading: boolean;
33
32
  schemasError: Error | null;
34
- refetchSchemas: () => void;
35
- // Connection status
36
- connectionStatus: ConnectionStatus;
37
- // Clear agent state
38
- clearAgentState: (agentId: string) => Promise<void>;
33
+ schemasLoading: boolean;
34
+ selectedAgent: string;
35
+ setInputMode: (mode: 'text' | 'form') => void;
36
+ setMessages: (messages: UIMessage[] | ((prev: UIMessage[]) => UIMessage[])) => void;
37
+ setSelectedAgent: (agentId: string) => void;
38
+ submitMessage: (value: string, mode?: 'text' | 'form') => Promise<void>;
39
+ }
40
+
41
+ export interface ErrorInfo {
42
+ message: string;
43
+ stack?: string;
44
+ code?: string;
45
+ cause?: unknown;
39
46
  }
@@ -1,14 +0,0 @@
1
- import React from 'react';
2
- export interface ChatProps {
3
- className?: string;
4
- schemaOpen: boolean;
5
- onSchemaToggle: () => void;
6
- emptyState?: React.ReactNode;
7
- }
8
- /**
9
- * Chat component - conversation and input area (everything except header)
10
- * Must be used within WorkbenchProvider
11
- */
12
- export declare function Chat({ className: _className, schemaOpen, onSchemaToggle, emptyState }: ChatProps): import("react/jsx-runtime").JSX.Element;
13
- export default Chat;
14
- //# sourceMappingURL=Chat.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/components/internal/Chat.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAexC,MAAM,WAAW,SAAS;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,EAAE,SAAS,2CA0KhG;AAED,eAAe,IAAI,CAAC"}