@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,5 +1,5 @@
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
3
 
4
4
  export interface AgentSchema {
5
5
  input?: {
@@ -13,18 +13,18 @@ export interface AgentSchema {
13
13
  }
14
14
 
15
15
  export interface AgentMetadata {
16
- id: string;
17
- name: string;
16
+ agentId: string;
18
17
  description?: string;
19
- version?: string;
20
18
  filename?: string;
19
+ id: string;
21
20
  identifier?: string;
22
- agentId: string;
21
+ name: string;
22
+ version?: string;
23
23
  }
24
24
 
25
25
  export interface AgentSchemaData {
26
- schema: AgentSchema;
27
26
  metadata: AgentMetadata;
27
+ schema: AgentSchema;
28
28
  }
29
29
 
30
30
  export interface AgentSchemasResponse {
@@ -32,15 +32,15 @@ export interface AgentSchemasResponse {
32
32
  }
33
33
 
34
34
  export interface UseAgentSchemasOptions {
35
- baseUrl?: string;
36
35
  apiKey?: string;
36
+ baseUrl?: string;
37
37
  enabled?: boolean;
38
38
  }
39
39
 
40
40
  export interface UseAgentSchemasResult {
41
41
  data: AgentSchemasResponse | null;
42
- isLoading: boolean;
43
42
  error: Error | null;
43
+ isLoading: boolean;
44
44
  refetch: () => void;
45
45
  }
46
46
 
@@ -84,7 +84,7 @@ export function useAgentSchemas(options: UseAgentSchemasOptions = {}): UseAgentS
84
84
  };
85
85
 
86
86
  if (apiKey) {
87
- headers['Authorization'] = `Bearer ${apiKey}`;
87
+ headers.Authorization = `Bearer ${apiKey}`;
88
88
  }
89
89
 
90
90
  const response = await fetch(url, {
@@ -96,26 +96,35 @@ export function useAgentSchemas(options: UseAgentSchemasOptions = {}): UseAgentS
96
96
  // Handle 404/500 gracefully without throwing
97
97
  if (response.status === 401) {
98
98
  setError(new Error('Unauthorized: Invalid or missing API key'));
99
+
99
100
  return;
100
101
  }
102
+
101
103
  if (response.status === 404 || response.status >= 500) {
102
104
  setError(new Error(`Server error: ${response.status} ${response.statusText}`));
105
+
103
106
  return;
104
107
  }
108
+
105
109
  setError(new Error(`HTTP ${response.status}: ${response.statusText}`));
110
+
106
111
  return;
107
112
  }
108
113
 
109
114
  try {
110
115
  const result = (await response.json()) as AgentSchemasResponse;
116
+
111
117
  setData(result);
112
118
  } catch (jsonError) {
113
119
  setError(new Error('Invalid JSON response from server'));
120
+
114
121
  console.error('Failed to parse JSON response:', jsonError);
115
122
  }
116
123
  } catch (err) {
117
124
  const error = err instanceof Error ? err : new Error('Unknown error occurred');
125
+
118
126
  setError(error);
127
+
119
128
  console.error('Failed to fetch agent schemas:', error);
120
129
  } finally {
121
130
  setIsLoading(false);
@@ -132,8 +141,8 @@ export function useAgentSchemas(options: UseAgentSchemasOptions = {}): UseAgentS
132
141
 
133
142
  return {
134
143
  data,
135
- isLoading,
136
144
  error,
145
+ isLoading,
137
146
  refetch,
138
147
  };
139
148
  }
@@ -148,10 +157,10 @@ export function useAgentSchema(agentName: string, options: UseAgentSchemasOption
148
157
 
149
158
  return {
150
159
  data: agentData,
151
- isLoading,
152
160
  error,
161
+ isLoading,
162
+ metadata: agentData?.metadata || null,
153
163
  refetch,
154
164
  schema: agentData?.schema || null,
155
- metadata: agentData?.metadata || null,
156
165
  };
157
166
  }
@@ -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"}