@lantos1618/better-ui 0.2.2 → 0.3.1

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 (59) hide show
  1. package/README.md +231 -148
  2. package/dist/index.d.mts +314 -0
  3. package/dist/index.d.ts +314 -0
  4. package/dist/index.js +522 -0
  5. package/dist/index.mjs +491 -0
  6. package/package.json +59 -20
  7. package/lib/aui/README.md +0 -136
  8. package/lib/aui/__tests__/aui-complete.test.ts +0 -251
  9. package/lib/aui/__tests__/aui-comprehensive.test.ts +0 -376
  10. package/lib/aui/__tests__/aui-concise.test.ts +0 -278
  11. package/lib/aui/__tests__/aui-integration.test.ts +0 -309
  12. package/lib/aui/__tests__/aui-simple.test.ts +0 -116
  13. package/lib/aui/__tests__/aui.test.ts +0 -269
  14. package/lib/aui/__tests__/concise-api.test.ts +0 -165
  15. package/lib/aui/__tests__/core.test.ts +0 -265
  16. package/lib/aui/__tests__/simple-api.test.ts +0 -200
  17. package/lib/aui/ai-assistant.ts +0 -408
  18. package/lib/aui/ai-control.ts +0 -353
  19. package/lib/aui/client/use-aui.ts +0 -55
  20. package/lib/aui/client-control.ts +0 -551
  21. package/lib/aui/client-executor.ts +0 -417
  22. package/lib/aui/components/ToolRenderer.tsx +0 -22
  23. package/lib/aui/core.ts +0 -137
  24. package/lib/aui/demo.tsx +0 -89
  25. package/lib/aui/examples/ai-complete-demo.tsx +0 -359
  26. package/lib/aui/examples/ai-control-demo.tsx +0 -356
  27. package/lib/aui/examples/ai-control-tools.ts +0 -308
  28. package/lib/aui/examples/concise-api.tsx +0 -153
  29. package/lib/aui/examples/index.tsx +0 -163
  30. package/lib/aui/examples/quick-demo.tsx +0 -91
  31. package/lib/aui/examples/simple-demo.tsx +0 -71
  32. package/lib/aui/examples/simple-tools.tsx +0 -160
  33. package/lib/aui/examples/user-api.tsx +0 -208
  34. package/lib/aui/examples/user-requested.tsx +0 -174
  35. package/lib/aui/examples/weather-search-tools.tsx +0 -119
  36. package/lib/aui/examples.tsx +0 -367
  37. package/lib/aui/hooks/useAUITool.ts +0 -142
  38. package/lib/aui/hooks/useAUIToolEnhanced.ts +0 -343
  39. package/lib/aui/hooks/useAUITools.ts +0 -195
  40. package/lib/aui/index.ts +0 -156
  41. package/lib/aui/provider.tsx +0 -45
  42. package/lib/aui/server-control.ts +0 -386
  43. package/lib/aui/server-executor.ts +0 -165
  44. package/lib/aui/server.ts +0 -167
  45. package/lib/aui/tool-registry.ts +0 -380
  46. package/lib/aui/tools/advanced-examples.tsx +0 -86
  47. package/lib/aui/tools/ai-complete.ts +0 -375
  48. package/lib/aui/tools/api-tools.tsx +0 -230
  49. package/lib/aui/tools/data-tools.tsx +0 -232
  50. package/lib/aui/tools/dom-tools.tsx +0 -202
  51. package/lib/aui/tools/examples.ts +0 -43
  52. package/lib/aui/tools/file-tools.tsx +0 -202
  53. package/lib/aui/tools/form-tools.tsx +0 -233
  54. package/lib/aui/tools/index.ts +0 -8
  55. package/lib/aui/tools/navigation-tools.tsx +0 -172
  56. package/lib/aui/tools/notification-tools.ts +0 -213
  57. package/lib/aui/tools/state-tools.tsx +0 -209
  58. package/lib/aui/types.ts +0 -47
  59. package/lib/aui/vercel-ai.ts +0 -100
@@ -1,417 +0,0 @@
1
- import { AUIContext } from './core';
2
- import { AIControlledTool } from './ai-control';
3
-
4
- export interface CacheStrategy {
5
- key: (toolName: string, input: any) => string;
6
- ttl?: number; // Time to live in milliseconds
7
- maxSize?: number; // Maximum number of cached items
8
- }
9
-
10
- export interface ClientExecutorOptions {
11
- baseUrl?: string;
12
- cache?: {
13
- enabled: boolean;
14
- strategy?: CacheStrategy;
15
- storage?: 'memory' | 'localStorage' | 'sessionStorage';
16
- };
17
- retry?: {
18
- attempts?: number;
19
- delay?: number;
20
- backoff?: 'linear' | 'exponential';
21
- };
22
- timeout?: number;
23
- headers?: HeadersInit;
24
- }
25
-
26
- interface CacheEntry {
27
- data: any;
28
- timestamp: number;
29
- ttl?: number;
30
- }
31
-
32
- export class ClientExecutor {
33
- private cache: Map<string, CacheEntry> = new Map();
34
- private options: Required<ClientExecutorOptions>;
35
- private localStorage?: Storage;
36
- private sessionStorage?: Storage;
37
-
38
- constructor(options: ClientExecutorOptions = {}) {
39
- this.options = {
40
- baseUrl: options.baseUrl || '/api/aui/execute',
41
- cache: {
42
- enabled: options.cache?.enabled ?? true,
43
- strategy: options.cache?.strategy || {
44
- key: (tool, input) => `${tool}:${JSON.stringify(input)}`,
45
- ttl: 5 * 60 * 1000, // 5 minutes default
46
- maxSize: 100,
47
- },
48
- storage: options.cache?.storage || 'memory',
49
- },
50
- retry: {
51
- attempts: options.retry?.attempts ?? 3,
52
- delay: options.retry?.delay ?? 1000,
53
- backoff: options.retry?.backoff || 'exponential',
54
- },
55
- timeout: options.timeout ?? 30000, // 30 seconds default
56
- headers: options.headers || {},
57
- };
58
-
59
- if (typeof window !== 'undefined') {
60
- this.localStorage = window.localStorage;
61
- this.sessionStorage = window.sessionStorage;
62
- }
63
- }
64
-
65
- async execute<TInput = any, TOutput = any>(
66
- toolName: string,
67
- input: TInput,
68
- context?: Partial<AUIContext>
69
- ): Promise<TOutput> {
70
- // Check cache first if enabled
71
- if (this.options.cache.enabled) {
72
- const cached = this.getFromCache(toolName, input);
73
- if (cached !== null) {
74
- return cached;
75
- }
76
- }
77
-
78
- // Execute with retry logic
79
- let lastError: Error | null = null;
80
- for (let attempt = 0; attempt < this.options.retry.attempts!; attempt++) {
81
- try {
82
- const result = await this.executeOnce<TInput, TOutput>(
83
- toolName,
84
- input,
85
- context
86
- );
87
-
88
- // Store in cache if enabled
89
- if (this.options.cache.enabled) {
90
- this.storeInCache(toolName, input, result);
91
- }
92
-
93
- return result;
94
- } catch (error) {
95
- lastError = error as Error;
96
-
97
- // Don't retry on certain errors
98
- if (error instanceof Error) {
99
- if (error.message.includes('Tool') && error.message.includes('not found')) {
100
- throw error; // Don't retry if tool doesn't exist
101
- }
102
- if (error.message.includes('Rate limit')) {
103
- throw error; // Don't retry on rate limit
104
- }
105
- }
106
-
107
- // Calculate delay for next attempt
108
- if (attempt < this.options.retry.attempts! - 1) {
109
- const delay = this.calculateRetryDelay(attempt);
110
- await this.sleep(delay);
111
- }
112
- }
113
- }
114
-
115
- throw lastError || new Error('Execution failed after retries');
116
- }
117
-
118
- private async executeOnce<TInput = any, TOutput = any>(
119
- toolName: string,
120
- input: TInput,
121
- context?: Partial<AUIContext>
122
- ): Promise<TOutput> {
123
- const controller = new AbortController();
124
- const timeoutId = setTimeout(
125
- () => controller.abort(),
126
- this.options.timeout
127
- );
128
-
129
- try {
130
- const response = await fetch(this.options.baseUrl, {
131
- method: 'POST',
132
- headers: {
133
- 'Content-Type': 'application/json',
134
- ...this.options.headers,
135
- },
136
- body: JSON.stringify({
137
- tool: toolName,
138
- input,
139
- context,
140
- }),
141
- signal: controller.signal,
142
- });
143
-
144
- clearTimeout(timeoutId);
145
-
146
- if (!response.ok) {
147
- const error = await response.json();
148
- throw new Error(error.error || `HTTP ${response.status}`);
149
- }
150
-
151
- const result = await response.json();
152
- return result.data || result;
153
- } catch (error) {
154
- clearTimeout(timeoutId);
155
-
156
- if (error instanceof Error && error.name === 'AbortError') {
157
- throw new Error(`Execution timeout after ${this.options.timeout}ms`);
158
- }
159
-
160
- throw error;
161
- }
162
- }
163
-
164
- private getFromCache(toolName: string, input: any): any | null {
165
- const key = this.options.cache.strategy!.key(toolName, input);
166
-
167
- // Check appropriate storage
168
- let entry: CacheEntry | null = null;
169
-
170
- switch (this.options.cache.storage) {
171
- case 'localStorage':
172
- if (this.localStorage) {
173
- const stored = this.localStorage.getItem(key);
174
- if (stored) {
175
- try {
176
- entry = JSON.parse(stored);
177
- } catch {
178
- // Invalid cache entry
179
- }
180
- }
181
- }
182
- break;
183
-
184
- case 'sessionStorage':
185
- if (this.sessionStorage) {
186
- const stored = this.sessionStorage.getItem(key);
187
- if (stored) {
188
- try {
189
- entry = JSON.parse(stored);
190
- } catch {
191
- // Invalid cache entry
192
- }
193
- }
194
- }
195
- break;
196
-
197
- default: // memory
198
- entry = this.cache.get(key) || null;
199
- }
200
-
201
- if (!entry) return null;
202
-
203
- // Check if entry is still valid
204
- const now = Date.now();
205
- const ttl = entry.ttl || this.options.cache.strategy!.ttl;
206
-
207
- if (ttl && now - entry.timestamp > ttl) {
208
- // Entry expired
209
- this.removeFromCache(key);
210
- return null;
211
- }
212
-
213
- return entry.data;
214
- }
215
-
216
- private storeInCache(toolName: string, input: any, data: any): void {
217
- const key = this.options.cache.strategy!.key(toolName, input);
218
- const entry: CacheEntry = {
219
- data,
220
- timestamp: Date.now(),
221
- ttl: this.options.cache.strategy!.ttl,
222
- };
223
-
224
- switch (this.options.cache.storage) {
225
- case 'localStorage':
226
- if (this.localStorage) {
227
- try {
228
- this.localStorage.setItem(key, JSON.stringify(entry));
229
- this.enforceMaxSize('localStorage');
230
- } catch {
231
- // Storage quota exceeded
232
- }
233
- }
234
- break;
235
-
236
- case 'sessionStorage':
237
- if (this.sessionStorage) {
238
- try {
239
- this.sessionStorage.setItem(key, JSON.stringify(entry));
240
- this.enforceMaxSize('sessionStorage');
241
- } catch {
242
- // Storage quota exceeded
243
- }
244
- }
245
- break;
246
-
247
- default: // memory
248
- this.cache.set(key, entry);
249
- this.enforceMaxSize('memory');
250
- }
251
- }
252
-
253
- private removeFromCache(key: string): void {
254
- switch (this.options.cache.storage) {
255
- case 'localStorage':
256
- if (this.localStorage) {
257
- this.localStorage.removeItem(key);
258
- }
259
- break;
260
-
261
- case 'sessionStorage':
262
- if (this.sessionStorage) {
263
- this.sessionStorage.removeItem(key);
264
- }
265
- break;
266
-
267
- default:
268
- this.cache.delete(key);
269
- }
270
- }
271
-
272
- private enforceMaxSize(storage: 'memory' | 'localStorage' | 'sessionStorage'): void {
273
- const maxSize = this.options.cache.strategy!.maxSize;
274
- if (!maxSize) return;
275
-
276
- if (storage === 'memory') {
277
- if (this.cache.size > maxSize) {
278
- // Remove oldest entries
279
- const entries = Array.from(this.cache.entries());
280
- entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
281
-
282
- const toRemove = entries.slice(0, entries.length - maxSize);
283
- toRemove.forEach(([key]) => this.cache.delete(key));
284
- }
285
- } else {
286
- const storageObj = storage === 'localStorage' ? this.localStorage : this.sessionStorage;
287
- if (!storageObj) return;
288
-
289
- // Get all cache keys
290
- const cacheKeys: Array<{ key: string; timestamp: number }> = [];
291
- for (let i = 0; i < storageObj.length; i++) {
292
- const key = storageObj.key(i);
293
- if (key) {
294
- try {
295
- const entry = JSON.parse(storageObj.getItem(key)!);
296
- if (entry && entry.timestamp) {
297
- cacheKeys.push({ key, timestamp: entry.timestamp });
298
- }
299
- } catch {
300
- // Skip invalid entries
301
- }
302
- }
303
- }
304
-
305
- if (cacheKeys.length > maxSize) {
306
- cacheKeys.sort((a, b) => a.timestamp - b.timestamp);
307
- const toRemove = cacheKeys.slice(0, cacheKeys.length - maxSize);
308
- toRemove.forEach(({ key }) => storageObj.removeItem(key));
309
- }
310
- }
311
- }
312
-
313
- private calculateRetryDelay(attempt: number): number {
314
- const baseDelay = this.options.retry.delay!;
315
-
316
- if (this.options.retry.backoff === 'exponential') {
317
- return baseDelay * Math.pow(2, attempt);
318
- }
319
-
320
- return baseDelay * (attempt + 1);
321
- }
322
-
323
- private sleep(ms: number): Promise<void> {
324
- return new Promise(resolve => setTimeout(resolve, ms));
325
- }
326
-
327
- clearCache(): void {
328
- switch (this.options.cache.storage) {
329
- case 'localStorage':
330
- if (this.localStorage) {
331
- this.localStorage.clear();
332
- }
333
- break;
334
-
335
- case 'sessionStorage':
336
- if (this.sessionStorage) {
337
- this.sessionStorage.clear();
338
- }
339
- break;
340
-
341
- default:
342
- this.cache.clear();
343
- }
344
- }
345
-
346
- getCacheStats(): {
347
- size: number;
348
- storage: string;
349
- enabled: boolean;
350
- } {
351
- let size = 0;
352
-
353
- switch (this.options.cache.storage) {
354
- case 'localStorage':
355
- size = this.localStorage?.length || 0;
356
- break;
357
-
358
- case 'sessionStorage':
359
- size = this.sessionStorage?.length || 0;
360
- break;
361
-
362
- default:
363
- size = this.cache.size;
364
- }
365
-
366
- return {
367
- size,
368
- storage: this.options.cache.storage!,
369
- enabled: this.options.cache.enabled,
370
- };
371
- }
372
- }
373
-
374
- // Default client executor instance
375
- export const clientExecutor = new ClientExecutor();
376
-
377
- // Enhanced client execution with optimistic updates
378
- export async function executeClientTool<TInput = any, TOutput = any>(
379
- toolName: string,
380
- input: TInput,
381
- options?: {
382
- optimistic?: () => TOutput;
383
- onSuccess?: (result: TOutput) => void;
384
- onError?: (error: Error) => void;
385
- context?: Partial<AUIContext>;
386
- }
387
- ): Promise<TOutput> {
388
- // Return optimistic result immediately if provided
389
- if (options?.optimistic) {
390
- const optimisticResult = options.optimistic();
391
-
392
- // Execute in background
393
- clientExecutor.execute<TInput, TOutput>(toolName, input, options?.context)
394
- .then(result => {
395
- options?.onSuccess?.(result);
396
- })
397
- .catch(error => {
398
- options?.onError?.(error);
399
- });
400
-
401
- return optimisticResult;
402
- }
403
-
404
- // Normal execution
405
- try {
406
- const result = await clientExecutor.execute<TInput, TOutput>(
407
- toolName,
408
- input,
409
- options?.context
410
- );
411
- options?.onSuccess?.(result);
412
- return result;
413
- } catch (error) {
414
- options?.onError?.(error as Error);
415
- throw error;
416
- }
417
- }
@@ -1,22 +0,0 @@
1
- import React from 'react';
2
- import { AUITool } from '../index';
3
-
4
- interface ToolRendererProps {
5
- tool: AUITool;
6
- input?: any;
7
- result?: any;
8
- loading?: boolean;
9
- error?: Error;
10
- }
11
-
12
- export function ToolRenderer({ tool, input, result, loading, error }: ToolRendererProps) {
13
- if (!tool.renderer) {
14
- return (
15
- <div className="p-4 bg-gray-100 rounded">
16
- <pre className="text-sm">{JSON.stringify(result, null, 2)}</pre>
17
- </div>
18
- );
19
- }
20
-
21
- return tool.renderer({ data: result, input, loading, error });
22
- }
package/lib/aui/core.ts DELETED
@@ -1,137 +0,0 @@
1
- import { ReactElement } from 'react';
2
- import { z } from 'zod';
3
-
4
- export interface AUIContext {
5
- cache: Map<string, any>;
6
- fetch: typeof fetch;
7
- user?: any;
8
- session?: any;
9
- env?: Record<string, string>;
10
- headers?: HeadersInit;
11
- cookies?: Record<string, string>;
12
- isServer?: boolean;
13
- }
14
-
15
- export interface ToolConfig<TInput, TOutput> {
16
- name: string;
17
- inputSchema?: z.ZodType<TInput>;
18
- executeHandler?: (params: { input: TInput; ctx?: AUIContext }) => Promise<TOutput> | TOutput;
19
- clientHandler?: (params: { input: TInput; ctx: AUIContext }) => Promise<TOutput> | TOutput;
20
- renderHandler?: (props: { data: TOutput; input?: TInput; loading?: boolean; error?: Error }) => ReactElement;
21
- middleware?: Array<(params: { input: TInput; ctx: AUIContext; next: () => Promise<TOutput> }) => Promise<TOutput>>;
22
- description?: string;
23
- tags?: string[];
24
- }
25
-
26
- export class AUITool<TInput = any, TOutput = any> {
27
- protected config: ToolConfig<TInput, TOutput> = { name: '' };
28
-
29
- constructor(name: string) {
30
- this.config.name = name;
31
- }
32
-
33
- input<T>(schema: z.ZodType<T>): AUITool<T, TOutput> {
34
- this.config.inputSchema = schema as any;
35
- return this as any;
36
- }
37
-
38
- execute<O>(handler: (params: { input: TInput; ctx?: AUIContext }) => O | Promise<O>): AUITool<TInput, O> {
39
- this.config.executeHandler = handler as any;
40
- return this as any;
41
- }
42
-
43
- clientExecute(handler: (params: { input: TInput; ctx: AUIContext }) => TOutput | Promise<TOutput>): this {
44
- this.config.clientHandler = handler;
45
- return this;
46
- }
47
-
48
- render(component: (props: { data: TOutput; input?: TInput; loading?: boolean; error?: Error }) => ReactElement): this {
49
- this.config.renderHandler = component;
50
- return this;
51
- }
52
-
53
- async run(input: TInput, ctx?: AUIContext): Promise<TOutput> {
54
- const validated = this.config.inputSchema ? this.config.inputSchema.parse(input) : input;
55
- const context = ctx || {
56
- cache: new Map(),
57
- fetch: globalThis.fetch?.bind(globalThis) || (() => Promise.reject(new Error('Fetch not available'))),
58
- isServer: typeof window === 'undefined',
59
- };
60
-
61
- // Apply middleware if present
62
- if (this.config.middleware?.length) {
63
- let index = 0;
64
- const next = async (): Promise<TOutput> => {
65
- if (index >= this.config.middleware!.length) {
66
- return this.executeCore(validated, context);
67
- }
68
- const middleware = this.config.middleware![index++];
69
- return middleware({ input: validated, ctx: context, next });
70
- };
71
- return next();
72
- }
73
-
74
- return this.executeCore(validated, context);
75
- }
76
-
77
- private async executeCore(input: TInput, ctx: AUIContext): Promise<TOutput> {
78
- // Use clientHandler if it exists and we're on the client
79
- if (!ctx.isServer && this.config.clientHandler) {
80
- return this.config.clientHandler({ input, ctx });
81
- }
82
-
83
- if (!this.config.executeHandler) {
84
- throw new Error(`Tool ${this.config.name} has no execute handler`);
85
- }
86
-
87
- return this.config.executeHandler({ input, ctx });
88
- }
89
-
90
- middleware(fn: (params: { input: TInput; ctx: AUIContext; next: () => Promise<TOutput> }) => Promise<TOutput>): this {
91
- if (!this.config.middleware) {
92
- this.config.middleware = [];
93
- }
94
- this.config.middleware.push(fn);
95
- return this;
96
- }
97
-
98
- describe(description: string): this {
99
- this.config.description = description;
100
- return this;
101
- }
102
-
103
- tag(...tags: string[]): this {
104
- if (!this.config.tags) {
105
- this.config.tags = [];
106
- }
107
- this.config.tags.push(...tags);
108
- return this;
109
- }
110
-
111
- get name() { return this.config.name; }
112
- get schema() { return this.config.inputSchema; }
113
- get inputSchema() { return this.config.inputSchema; }
114
- get outputSchema() { return undefined; } // Can be extended if needed
115
- get isServerOnly() { return !this.config.clientHandler; }
116
- get metadata() { return { description: this.config.description, tags: this.config.tags }; }
117
- get renderer() { return this.config.renderHandler; }
118
- get description() { return this.config.description; }
119
- get tags() { return this.config.tags || []; }
120
-
121
- toJSON() {
122
- return {
123
- name: this.config.name,
124
- description: this.config.description,
125
- tags: this.config.tags || [],
126
- hasInput: !!this.config.inputSchema,
127
- hasExecute: !!this.config.executeHandler,
128
- hasClientExecute: !!this.config.clientHandler,
129
- hasRender: !!this.config.renderHandler,
130
- hasMiddleware: !!(this.config.middleware && this.config.middleware.length > 0)
131
- };
132
- }
133
-
134
- getConfig(): Readonly<ToolConfig<TInput, TOutput>> {
135
- return { ...this.config };
136
- }
137
- }
package/lib/aui/demo.tsx DELETED
@@ -1,89 +0,0 @@
1
- import aui from './index';
2
- import { z } from 'zod';
3
-
4
- // ============================================
5
- // EXACT API AS REQUESTED BY USER
6
- // ============================================
7
-
8
- // Simple tool - just 2 methods
9
- const simpleTool = aui
10
- .tool('weather')
11
- .input(z.object({ city: z.string() }))
12
- .execute(async ({ input }) => ({ temp: 72, city: input.city }))
13
- .render(({ data }) => <div>{data.city}: {data.temp}°</div>);
14
-
15
- // Complex tool - adds client optimization
16
- const complexTool = aui
17
- .tool('search')
18
- .input(z.object({ query: z.string() }))
19
- .execute(async ({ input }) => {
20
- // Mock database search
21
- return { results: [`Result for ${input.query}`] };
22
- })
23
- .clientExecute(async ({ input, ctx }) => {
24
- // Only when you need caching, offline, etc.
25
- const cached = ctx.cache.get(input.query);
26
- return cached || ctx.fetch('/api/tools/search', {
27
- method: 'POST',
28
- headers: { 'Content-Type': 'application/json' },
29
- body: JSON.stringify(input)
30
- }).then(r => r.json());
31
- })
32
- .render(({ data }) => <SearchResults results={data} />);
33
-
34
- // Component for rendering search results
35
- function SearchResults({ results }: { results: any }) {
36
- return (
37
- <div>
38
- {results.results?.map((r: string, i: number) => (
39
- <div key={i}>{r}</div>
40
- ))}
41
- </div>
42
- );
43
- }
44
-
45
- // ============================================
46
- // USAGE EXAMPLES
47
- // ============================================
48
-
49
- // Direct execution
50
- async function exampleUsage() {
51
- const ctx = aui.createContext();
52
-
53
- // Execute weather tool
54
- const weatherResult = await simpleTool.run({ city: 'Tokyo' }, ctx);
55
- console.log(weatherResult); // { temp: 72, city: 'Tokyo' }
56
-
57
- // Execute search tool
58
- const searchResult = await complexTool.run({ query: 'AI tools' }, ctx);
59
- console.log(searchResult); // { results: ['Result for AI tools'] }
60
- }
61
-
62
- // React component usage
63
- import { useAUITool } from './hooks/useAUITool';
64
-
65
- export function WeatherWidget() {
66
- const { execute, data, loading } = useAUITool(simpleTool);
67
-
68
- return (
69
- <div>
70
- <button onClick={() => execute({ city: 'Tokyo' })}>
71
- Get Weather
72
- </button>
73
- {loading && <span>Loading...</span>}
74
- {data && simpleTool.renderer && simpleTool.renderer({ data })}
75
- </div>
76
- );
77
- }
78
-
79
- // AI Agent can discover and use tools
80
- export function getToolsForAI() {
81
- return aui.getTools().map((tool: any) => ({
82
- name: tool.name,
83
- description: tool.description,
84
- schema: tool.schema,
85
- execute: (input: any) => tool.run(input)
86
- }));
87
- }
88
-
89
- export { simpleTool, complexTool };