@lantos1618/better-ui 0.1.0

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 (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +190 -0
  3. package/lib/aui/README.md +136 -0
  4. package/lib/aui/__tests__/aui-complete.test.ts +251 -0
  5. package/lib/aui/__tests__/aui-comprehensive.test.ts +376 -0
  6. package/lib/aui/__tests__/aui-concise.test.ts +278 -0
  7. package/lib/aui/__tests__/aui-integration.test.ts +309 -0
  8. package/lib/aui/__tests__/aui-simple.test.ts +116 -0
  9. package/lib/aui/__tests__/aui.test.ts +269 -0
  10. package/lib/aui/__tests__/concise-api.test.ts +165 -0
  11. package/lib/aui/__tests__/core.test.ts +265 -0
  12. package/lib/aui/__tests__/simple-api.test.ts +200 -0
  13. package/lib/aui/ai-assistant.ts +408 -0
  14. package/lib/aui/ai-control.ts +353 -0
  15. package/lib/aui/client/use-aui.ts +55 -0
  16. package/lib/aui/client-control.ts +551 -0
  17. package/lib/aui/client-executor.ts +417 -0
  18. package/lib/aui/components/ToolRenderer.tsx +22 -0
  19. package/lib/aui/core.ts +137 -0
  20. package/lib/aui/demo.tsx +89 -0
  21. package/lib/aui/examples/ai-complete-demo.tsx +359 -0
  22. package/lib/aui/examples/ai-control-demo.tsx +356 -0
  23. package/lib/aui/examples/ai-control-tools.ts +308 -0
  24. package/lib/aui/examples/concise-api.tsx +153 -0
  25. package/lib/aui/examples/index.tsx +163 -0
  26. package/lib/aui/examples/quick-demo.tsx +91 -0
  27. package/lib/aui/examples/simple-demo.tsx +71 -0
  28. package/lib/aui/examples/simple-tools.tsx +160 -0
  29. package/lib/aui/examples/user-api.tsx +208 -0
  30. package/lib/aui/examples/user-requested.tsx +174 -0
  31. package/lib/aui/examples/weather-search-tools.tsx +119 -0
  32. package/lib/aui/examples.tsx +367 -0
  33. package/lib/aui/hooks/useAUITool.ts +142 -0
  34. package/lib/aui/hooks/useAUIToolEnhanced.ts +343 -0
  35. package/lib/aui/hooks/useAUITools.ts +195 -0
  36. package/lib/aui/index.ts +156 -0
  37. package/lib/aui/provider.tsx +45 -0
  38. package/lib/aui/server-control.ts +386 -0
  39. package/lib/aui/server-executor.ts +165 -0
  40. package/lib/aui/server.ts +167 -0
  41. package/lib/aui/tool-registry.ts +380 -0
  42. package/lib/aui/tools/advanced-examples.tsx +86 -0
  43. package/lib/aui/tools/ai-complete.ts +375 -0
  44. package/lib/aui/tools/api-tools.tsx +230 -0
  45. package/lib/aui/tools/data-tools.tsx +232 -0
  46. package/lib/aui/tools/dom-tools.tsx +202 -0
  47. package/lib/aui/tools/examples.ts +43 -0
  48. package/lib/aui/tools/file-tools.tsx +202 -0
  49. package/lib/aui/tools/form-tools.tsx +233 -0
  50. package/lib/aui/tools/index.ts +8 -0
  51. package/lib/aui/tools/navigation-tools.tsx +172 -0
  52. package/lib/aui/tools/notification-tools.ts +213 -0
  53. package/lib/aui/tools/state-tools.tsx +209 -0
  54. package/lib/aui/types.ts +47 -0
  55. package/lib/aui/vercel-ai.ts +100 -0
  56. package/package.json +51 -0
@@ -0,0 +1,343 @@
1
+ import { useState, useCallback, useRef, useEffect } from 'react';
2
+ import { AUITool, AUIContext } from '../index';
3
+
4
+ export interface UseAUIToolOptions<TInput, TOutput> {
5
+ // Caching
6
+ cacheKey?: string | ((input: TInput) => string);
7
+ cacheDuration?: number; // milliseconds
8
+
9
+ // Retry
10
+ retryCount?: number;
11
+ retryDelay?: number | ((attempt: number) => number);
12
+
13
+ // Callbacks
14
+ onSuccess?: (data: TOutput, input: TInput) => void;
15
+ onError?: (error: Error, input: TInput) => void;
16
+ onLoadingChange?: (loading: boolean) => void;
17
+
18
+ // Debounce/Throttle
19
+ debounceMs?: number;
20
+ throttleMs?: number;
21
+
22
+ // Auto-execute
23
+ autoExecute?: boolean;
24
+ autoExecuteInput?: TInput;
25
+
26
+ // Polling
27
+ pollingInterval?: number;
28
+ pollingCondition?: (data: TOutput | null) => boolean;
29
+
30
+ // Context
31
+ context?: Partial<AUIContext>;
32
+ }
33
+
34
+ export interface UseAUIToolResult<TInput, TOutput> {
35
+ execute: (input: TInput) => Promise<TOutput>;
36
+ cancel: () => void;
37
+ reset: () => void;
38
+ data: TOutput | null;
39
+ error: Error | null;
40
+ loading: boolean;
41
+ isSuccess: boolean;
42
+ isError: boolean;
43
+ isIdle: boolean;
44
+ executionCount: number;
45
+ lastExecutedAt: Date | null;
46
+ }
47
+
48
+ export function useAUIToolEnhanced<TInput = any, TOutput = any>(
49
+ tool: AUITool<TInput, TOutput>,
50
+ options: UseAUIToolOptions<TInput, TOutput> = {}
51
+ ): UseAUIToolResult<TInput, TOutput> {
52
+ const [data, setData] = useState<TOutput | null>(null);
53
+ const [error, setError] = useState<Error | null>(null);
54
+ const [loading, setLoading] = useState(false);
55
+ const [executionCount, setExecutionCount] = useState(0);
56
+ const [lastExecutedAt, setLastExecutedAt] = useState<Date | null>(null);
57
+
58
+ const abortControllerRef = useRef<AbortController | null>(null);
59
+ const debounceTimerRef = useRef<NodeJS.Timeout | null>(null);
60
+ const throttleTimerRef = useRef<NodeJS.Timeout | null>(null);
61
+ const pollingTimerRef = useRef<NodeJS.Timeout | null>(null);
62
+ const cacheRef = useRef<Map<string, { data: TOutput; expires: number }>>(new Map());
63
+
64
+ // Clear timers on unmount
65
+ useEffect(() => {
66
+ return () => {
67
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
68
+ if (throttleTimerRef.current) clearTimeout(throttleTimerRef.current);
69
+ if (pollingTimerRef.current) clearInterval(pollingTimerRef.current);
70
+ if (abortControllerRef.current) abortControllerRef.current.abort();
71
+ };
72
+ }, []);
73
+
74
+ // Handle loading state changes
75
+ useEffect(() => {
76
+ options.onLoadingChange?.(loading);
77
+ }, [loading, options]);
78
+
79
+ // Get cache key for input
80
+ const getCacheKey = useCallback((input: TInput): string => {
81
+ if (!options.cacheKey) return '';
82
+ if (typeof options.cacheKey === 'function') {
83
+ return options.cacheKey(input);
84
+ }
85
+ return options.cacheKey;
86
+ }, [options]);
87
+
88
+ // Check cache
89
+ const checkCache = useCallback((input: TInput): TOutput | null => {
90
+ if (!options.cacheKey) return null;
91
+
92
+ const key = getCacheKey(input);
93
+ const cached = cacheRef.current.get(key);
94
+
95
+ if (cached && cached.expires > Date.now()) {
96
+ return cached.data;
97
+ }
98
+
99
+ return null;
100
+ }, [getCacheKey, options.cacheKey]);
101
+
102
+ // Set cache
103
+ const setCache = useCallback((input: TInput, data: TOutput) => {
104
+ if (!options.cacheKey) return;
105
+
106
+ const key = getCacheKey(input);
107
+ const expires = Date.now() + (options.cacheDuration || 5 * 60 * 1000);
108
+ cacheRef.current.set(key, { data, expires });
109
+ }, [getCacheKey, options.cacheKey, options.cacheDuration]);
110
+
111
+ // Execute with retry
112
+ const executeWithRetry = useCallback(async (
113
+ input: TInput,
114
+ attempt: number = 0
115
+ ): Promise<TOutput> => {
116
+ try {
117
+ const context: AUIContext = {
118
+ cache: new Map(),
119
+ fetch: globalThis.fetch,
120
+ isServer: typeof window === 'undefined',
121
+ ...options.context
122
+ };
123
+
124
+ const result = await tool.run(input, context);
125
+ return result;
126
+ } catch (error) {
127
+ const maxRetries = options.retryCount || 0;
128
+
129
+ if (attempt < maxRetries) {
130
+ const delay = typeof options.retryDelay === 'function'
131
+ ? options.retryDelay(attempt)
132
+ : options.retryDelay || Math.pow(2, attempt) * 1000;
133
+
134
+ await new Promise(resolve => setTimeout(resolve, delay));
135
+ return executeWithRetry(input, attempt + 1);
136
+ }
137
+
138
+ throw error;
139
+ }
140
+ }, [tool, options]);
141
+
142
+ // Main execute function
143
+ const execute = useCallback(async (input: TInput): Promise<TOutput> => {
144
+ // Check cache first
145
+ const cached = checkCache(input);
146
+ if (cached) {
147
+ setData(cached);
148
+ setError(null);
149
+ options.onSuccess?.(cached, input);
150
+ return cached;
151
+ }
152
+
153
+ // Cancel previous request
154
+ if (abortControllerRef.current) {
155
+ abortControllerRef.current.abort();
156
+ }
157
+
158
+ // Create new abort controller
159
+ abortControllerRef.current = new AbortController();
160
+
161
+ setLoading(true);
162
+ setError(null);
163
+ setExecutionCount(prev => prev + 1);
164
+ setLastExecutedAt(new Date());
165
+
166
+ try {
167
+ const result = await executeWithRetry(input);
168
+
169
+ // Check if aborted
170
+ if (abortControllerRef.current?.signal.aborted) {
171
+ throw new Error('Request cancelled');
172
+ }
173
+
174
+ setData(result);
175
+ setCache(input, result);
176
+ options.onSuccess?.(result, input);
177
+
178
+ // Start polling if configured
179
+ if (options.pollingInterval && options.pollingCondition?.(result)) {
180
+ if (pollingTimerRef.current) clearInterval(pollingTimerRef.current);
181
+
182
+ pollingTimerRef.current = setInterval(() => {
183
+ execute(input);
184
+ }, options.pollingInterval);
185
+ }
186
+
187
+ return result;
188
+ } catch (err) {
189
+ const error = err as Error;
190
+ setError(error);
191
+ options.onError?.(error, input);
192
+ throw error;
193
+ } finally {
194
+ setLoading(false);
195
+ }
196
+ }, [
197
+ checkCache,
198
+ executeWithRetry,
199
+ setCache,
200
+ options
201
+ ]);
202
+
203
+ // Debounced execute
204
+ const debouncedExecute = useCallback((input: TInput): Promise<TOutput> => {
205
+ return new Promise((resolve, reject) => {
206
+ if (debounceTimerRef.current) {
207
+ clearTimeout(debounceTimerRef.current);
208
+ }
209
+
210
+ debounceTimerRef.current = setTimeout(() => {
211
+ execute(input).then(resolve).catch(reject);
212
+ }, options.debounceMs);
213
+ });
214
+ }, [execute, options.debounceMs]);
215
+
216
+ // Throttled execute
217
+ const throttledExecute = useCallback((input: TInput): Promise<TOutput> => {
218
+ return new Promise((resolve, reject) => {
219
+ if (throttleTimerRef.current) {
220
+ reject(new Error('Request throttled'));
221
+ return;
222
+ }
223
+
224
+ throttleTimerRef.current = setTimeout(() => {
225
+ throttleTimerRef.current = null;
226
+ }, options.throttleMs);
227
+
228
+ execute(input).then(resolve).catch(reject);
229
+ });
230
+ }, [execute, options.throttleMs]);
231
+
232
+ // Choose appropriate execute function
233
+ const finalExecute = options.debounceMs
234
+ ? debouncedExecute
235
+ : options.throttleMs
236
+ ? throttledExecute
237
+ : execute;
238
+
239
+ // Cancel execution
240
+ const cancel = useCallback(() => {
241
+ if (abortControllerRef.current) {
242
+ abortControllerRef.current.abort();
243
+ abortControllerRef.current = null;
244
+ }
245
+ if (debounceTimerRef.current) {
246
+ clearTimeout(debounceTimerRef.current);
247
+ debounceTimerRef.current = null;
248
+ }
249
+ if (pollingTimerRef.current) {
250
+ clearInterval(pollingTimerRef.current);
251
+ pollingTimerRef.current = null;
252
+ }
253
+ setLoading(false);
254
+ }, []);
255
+
256
+ // Reset state
257
+ const reset = useCallback(() => {
258
+ cancel();
259
+ setData(null);
260
+ setError(null);
261
+ setLoading(false);
262
+ setExecutionCount(0);
263
+ setLastExecutedAt(null);
264
+ cacheRef.current.clear();
265
+ }, [cancel]);
266
+
267
+ // Auto-execute on mount
268
+ useEffect(() => {
269
+ if (options.autoExecute && options.autoExecuteInput) {
270
+ finalExecute(options.autoExecuteInput);
271
+ }
272
+ }, [finalExecute, options.autoExecute, options.autoExecuteInput]);
273
+
274
+ return {
275
+ execute: finalExecute,
276
+ cancel,
277
+ reset,
278
+ data,
279
+ error,
280
+ loading,
281
+ isSuccess: !loading && !error && data !== null,
282
+ isError: !loading && error !== null,
283
+ isIdle: !loading && !error && data === null,
284
+ executionCount,
285
+ lastExecutedAt
286
+ };
287
+ }
288
+
289
+ // Batch execution hook
290
+ export function useAUIToolBatch<TInput = any, TOutput = any>(
291
+ tool: AUITool<TInput, TOutput>,
292
+ options: UseAUIToolOptions<TInput, TOutput> = {}
293
+ ) {
294
+ const [results, setResults] = useState<Map<string, TOutput>>(new Map());
295
+ const [errors, setErrors] = useState<Map<string, Error>>(new Map());
296
+ const [loading, setLoading] = useState(false);
297
+
298
+ const executeBatch = useCallback(async (inputs: TInput[]): Promise<Map<string, TOutput>> => {
299
+ setLoading(true);
300
+ const newResults = new Map<string, TOutput>();
301
+ const newErrors = new Map<string, Error>();
302
+
303
+ try {
304
+ const promises = inputs.map(async (input, index) => {
305
+ const key = JSON.stringify(input);
306
+ try {
307
+ const context: AUIContext = {
308
+ cache: new Map(),
309
+ fetch: globalThis.fetch,
310
+ isServer: typeof window === 'undefined',
311
+ ...options.context
312
+ };
313
+
314
+ const result = await tool.run(input, context);
315
+ newResults.set(key, result);
316
+ return result;
317
+ } catch (error) {
318
+ newErrors.set(key, error as Error);
319
+ throw error;
320
+ }
321
+ });
322
+
323
+ await Promise.allSettled(promises);
324
+
325
+ setResults(newResults);
326
+ setErrors(newErrors);
327
+
328
+ return newResults;
329
+ } finally {
330
+ setLoading(false);
331
+ }
332
+ }, [tool, options.context]);
333
+
334
+ return {
335
+ executeBatch,
336
+ results,
337
+ errors,
338
+ loading
339
+ };
340
+ }
341
+
342
+ // Export all hooks
343
+ export { useAUIToolEnhanced as default };
@@ -0,0 +1,195 @@
1
+ 'use client';
2
+
3
+ import { useState, useCallback, useRef } from 'react';
4
+ import aui, { AUITool, AUIContext } from '../index';
5
+
6
+ export interface UseAUIToolsOptions {
7
+ cache?: boolean;
8
+ optimistic?: boolean;
9
+ retry?: number;
10
+ onSuccess?: (result: any, tool: string) => void;
11
+ onError?: (error: Error, tool: string) => void;
12
+ }
13
+
14
+ export function useAUITools(options: UseAUIToolsOptions = {}) {
15
+ const [loading, setLoading] = useState<Record<string, boolean>>({});
16
+ const [errors, setErrors] = useState<Record<string, Error | null>>({});
17
+ const [data, setData] = useState<Record<string, any>>({});
18
+ const cache = useRef(new Map<string, any>());
19
+
20
+ const execute = useCallback(async <TInput = any, TOutput = any>(
21
+ toolName: string,
22
+ input: TInput
23
+ ): Promise<TOutput | null> => {
24
+ setLoading(prev => ({ ...prev, [toolName]: true }));
25
+ setErrors(prev => ({ ...prev, [toolName]: null }));
26
+
27
+ try {
28
+ // Check cache if enabled
29
+ if (options.cache) {
30
+ const cacheKey = `${toolName}:${JSON.stringify(input)}`;
31
+ if (cache.current.has(cacheKey)) {
32
+ const cached = cache.current.get(cacheKey);
33
+ setData(prev => ({ ...prev, [toolName]: cached }));
34
+ setLoading(prev => ({ ...prev, [toolName]: false }));
35
+ return cached;
36
+ }
37
+ }
38
+
39
+ // Create context
40
+ const ctx: AUIContext = {
41
+ cache: cache.current,
42
+ fetch: globalThis.fetch,
43
+ isServer: false,
44
+ };
45
+
46
+ // Get tool
47
+ const tool = aui.get(toolName);
48
+ let result: TOutput;
49
+
50
+ if (tool) {
51
+ // Execute locally if tool exists
52
+ result = await tool.run(input, ctx);
53
+ } else {
54
+ // Execute via API
55
+ const response = await fetch(`/api/tools/${toolName}`, {
56
+ method: 'POST',
57
+ headers: { 'Content-Type': 'application/json' },
58
+ body: JSON.stringify(input),
59
+ });
60
+
61
+ if (!response.ok) {
62
+ throw new Error(`Failed to execute tool: ${response.statusText}`);
63
+ }
64
+
65
+ const data = await response.json();
66
+ result = data.data;
67
+ }
68
+
69
+ // Cache result if enabled
70
+ if (options.cache) {
71
+ const cacheKey = `${toolName}:${JSON.stringify(input)}`;
72
+ cache.current.set(cacheKey, result);
73
+ }
74
+
75
+ setData(prev => ({ ...prev, [toolName]: result }));
76
+ options.onSuccess?.(result, toolName);
77
+
78
+ return result;
79
+ } catch (error) {
80
+ const err = error instanceof Error ? error : new Error('Unknown error');
81
+ setErrors(prev => ({ ...prev, [toolName]: err }));
82
+ options.onError?.(err, toolName);
83
+
84
+ // Retry logic
85
+ if (options.retry && options.retry > 0) {
86
+ await new Promise(resolve => setTimeout(resolve, 1000));
87
+ return execute(toolName, input);
88
+ }
89
+
90
+ return null;
91
+ } finally {
92
+ setLoading(prev => ({ ...prev, [toolName]: false }));
93
+ }
94
+ }, [options]);
95
+
96
+ const executeBatch = useCallback(async (
97
+ executions: Array<{ tool: string; input: any }>
98
+ ) => {
99
+ setLoading(prev => {
100
+ const newLoading = { ...prev };
101
+ executions.forEach(exec => {
102
+ newLoading[exec.tool] = true;
103
+ });
104
+ return newLoading;
105
+ });
106
+
107
+ try {
108
+ const response = await fetch('/api/aui/batch', {
109
+ method: 'POST',
110
+ headers: { 'Content-Type': 'application/json' },
111
+ body: JSON.stringify({ executions }),
112
+ });
113
+
114
+ if (!response.ok) {
115
+ throw new Error('Batch execution failed');
116
+ }
117
+
118
+ const { results } = await response.json();
119
+
120
+ results.forEach((result: any) => {
121
+ if (result.success) {
122
+ setData(prev => ({ ...prev, [result.tool]: result.data }));
123
+ setErrors(prev => ({ ...prev, [result.tool]: null }));
124
+ options.onSuccess?.(result.data, result.tool);
125
+ } else {
126
+ const error = new Error(result.error);
127
+ setErrors(prev => ({ ...prev, [result.tool]: error }));
128
+ options.onError?.(error, result.tool);
129
+ }
130
+ });
131
+
132
+ return results;
133
+ } catch (error) {
134
+ const err = error instanceof Error ? error : new Error('Batch execution failed');
135
+ executions.forEach(exec => {
136
+ setErrors(prev => ({ ...prev, [exec.tool]: err }));
137
+ });
138
+ throw err;
139
+ } finally {
140
+ setLoading(prev => {
141
+ const newLoading = { ...prev };
142
+ executions.forEach(exec => {
143
+ newLoading[exec.tool] = false;
144
+ });
145
+ return newLoading;
146
+ });
147
+ }
148
+ }, [options]);
149
+
150
+ const reset = useCallback((toolName?: string) => {
151
+ if (toolName) {
152
+ setData(prev => ({ ...prev, [toolName]: undefined }));
153
+ setErrors(prev => ({ ...prev, [toolName]: null }));
154
+ setLoading(prev => ({ ...prev, [toolName]: false }));
155
+ } else {
156
+ setData({});
157
+ setErrors({});
158
+ setLoading({});
159
+ cache.current.clear();
160
+ }
161
+ }, []);
162
+
163
+ const clearCache = useCallback(() => {
164
+ cache.current.clear();
165
+ }, []);
166
+
167
+ return {
168
+ execute,
169
+ executeBatch,
170
+ loading,
171
+ errors,
172
+ data,
173
+ reset,
174
+ clearCache,
175
+ isLoading: (tool: string) => loading[tool] || false,
176
+ getError: (tool: string) => errors[tool] || null,
177
+ getData: (tool: string) => data[tool],
178
+ };
179
+ }
180
+
181
+ export function useAUITool<TInput = any, TOutput = any>(
182
+ toolOrName: string | AUITool<TInput, TOutput>,
183
+ options?: UseAUIToolsOptions
184
+ ) {
185
+ const toolName = typeof toolOrName === 'string' ? toolOrName : toolOrName.name;
186
+ const tools = useAUITools(options);
187
+
188
+ return {
189
+ execute: (input: TInput) => tools.execute<TInput, TOutput>(toolName, input),
190
+ loading: tools.isLoading(toolName),
191
+ error: tools.getError(toolName),
192
+ data: tools.getData(toolName) as TOutput | undefined,
193
+ reset: () => tools.reset(toolName),
194
+ };
195
+ }
@@ -0,0 +1,156 @@
1
+ import { AUITool, AUIContext, ToolConfig } from './core';
2
+
3
+ export { AUITool } from './core';
4
+ export type { AUIContext, ToolConfig } from './core';
5
+
6
+ export class AUI {
7
+ private tools = new Map<string, AUITool>();
8
+
9
+ tool(name: string): AUITool {
10
+ const t = new AUITool(name);
11
+ this.tools.set(name, t);
12
+ return t;
13
+ }
14
+
15
+ get(name: string): AUITool | undefined {
16
+ return this.tools.get(name);
17
+ }
18
+
19
+ getTool(name: string): AUITool | undefined {
20
+ return this.tools.get(name);
21
+ }
22
+
23
+ async execute<TInput = any, TOutput = any>(
24
+ name: string,
25
+ input: TInput,
26
+ ctx?: AUIContext
27
+ ): Promise<TOutput> {
28
+ const tool = this.get(name);
29
+ if (!tool) throw new Error(`Tool "${name}" not found`);
30
+ return await tool.run(input, ctx || this.createContext());
31
+ }
32
+
33
+ createContext(additions?: Partial<AUIContext>): AUIContext {
34
+ return {
35
+ cache: new Map(),
36
+ fetch: globalThis.fetch?.bind(globalThis) || (() => Promise.reject(new Error('Fetch not available'))),
37
+ isServer: typeof window === 'undefined',
38
+ ...additions,
39
+ };
40
+ }
41
+
42
+ list(): AUITool[] {
43
+ return Array.from(this.tools.values());
44
+ }
45
+
46
+ getTools(): AUITool[] {
47
+ return this.list();
48
+ }
49
+
50
+ getToolNames(): string[] {
51
+ return Array.from(this.tools.keys());
52
+ }
53
+
54
+ has(name: string): boolean {
55
+ return this.tools.has(name);
56
+ }
57
+
58
+ clear(): void {
59
+ this.tools.clear();
60
+ }
61
+
62
+ remove(name: string): boolean {
63
+ return this.tools.delete(name);
64
+ }
65
+
66
+ findByTag(tag: string): AUITool[] {
67
+ return this.list().filter(tool => tool.tags.includes(tag));
68
+ }
69
+
70
+ findByTags(...tags: string[]): AUITool[] {
71
+ return this.list().filter(tool =>
72
+ tags.every(tag => tool.tags.includes(tag))
73
+ );
74
+ }
75
+ }
76
+
77
+ const aui: AUI = new AUI();
78
+
79
+ export type InferToolInput<T> = T extends AUITool<infer I, any> ? I : never;
80
+ export type InferToolOutput<T> = T extends AUITool<any, infer O> ? O : never;
81
+
82
+ export type ToolDefinition<TInput = any, TOutput = any> = {
83
+ tool: AUITool<TInput, TOutput>;
84
+ input: TInput;
85
+ output: TOutput;
86
+ };
87
+
88
+ export type ExtractTools<T> = T extends { [K in keyof T]: AUITool<infer I, infer O> }
89
+ ? { [K in keyof T]: ToolDefinition<InferToolInput<T[K]>, InferToolOutput<T[K]>> }
90
+ : never;
91
+
92
+ // Re-export everything for convenience
93
+ export { z } from 'zod';
94
+ export { useAUITool, useAUI } from './hooks/useAUITool';
95
+ export { useAUITools } from './hooks/useAUITools';
96
+ export { AUIProvider, useAUIContext, useAUIInstance } from './provider';
97
+ export {
98
+ createAITool,
99
+ AIControlledTool,
100
+ aiControlSystem,
101
+ aiTools,
102
+ type AIControlOptions
103
+ } from './ai-control';
104
+
105
+ // Export all pre-built tools
106
+ export * from './tools';
107
+
108
+ // Client control exports
109
+ export {
110
+ clientTools,
111
+ clientControlSystem,
112
+ createClientControlSystem,
113
+ type ClientControlContext
114
+ } from './client-control';
115
+
116
+ // Tool registry and discovery
117
+ export {
118
+ ToolRegistry,
119
+ ToolDiscovery,
120
+ globalToolRegistry,
121
+ toolDiscovery,
122
+ type ToolMetadata
123
+ } from './tool-registry';
124
+
125
+ // Client executor for optimized client-side execution
126
+ export {
127
+ ClientExecutor,
128
+ clientExecutor,
129
+ executeClientTool,
130
+ type ClientExecutorOptions,
131
+ type CacheStrategy
132
+ } from './client-executor';
133
+
134
+ // AI Assistant integration
135
+ export {
136
+ AIAssistant,
137
+ createAIAssistant,
138
+ formatToolForLLM,
139
+ assistants,
140
+ type AIAssistantConfig,
141
+ type AIToolCall,
142
+ type AIConversationMessage
143
+ } from './ai-assistant';
144
+
145
+ // Vercel AI SDK integration
146
+ export {
147
+ convertToVercelTool,
148
+ createVercelTools,
149
+ createAUIToolFromVercel,
150
+ executeToolWithStreaming,
151
+ vercelAIIntegration
152
+ } from './vercel-ai';
153
+
154
+ // Example tools - exported separately to avoid circular dependencies
155
+
156
+ export default aui;