@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,153 @@
1
+ import aui, { z } from '../index';
2
+
3
+ // Simple tool - just 2 methods
4
+ export const simpleTool = aui
5
+ .tool('weather')
6
+ .input(z.object({ city: z.string() }))
7
+ .execute(async ({ input }) => ({ temp: 72, city: input.city }));
8
+
9
+ // With render
10
+ export const withRenderTool = aui
11
+ .tool('temperature')
12
+ .input(z.object({ city: z.string() }))
13
+ .execute(async ({ input }) => ({ temp: 72, city: input.city }))
14
+ .render(({ data }) => <div>{data.city}: {data.temp}°</div>);
15
+
16
+ // Complex tool - adds client optimization
17
+ export const complexTool = aui
18
+ .tool('search')
19
+ .input(z.object({ query: z.string() }))
20
+ .execute(async ({ input }) => {
21
+ // Server-side: database search
22
+ return { results: [`Server result for ${input.query}`] };
23
+ })
24
+ .clientExecute(async ({ input, ctx }) => {
25
+ // Client-side: check cache first, then fetch
26
+ const cached = ctx.cache.get(input.query);
27
+ if (cached) return cached;
28
+
29
+ const result = await ctx.fetch('/api/tools/search', {
30
+ method: 'POST',
31
+ body: JSON.stringify(input)
32
+ }).then(r => r.json());
33
+
34
+ ctx.cache.set(input.query, result);
35
+ return result;
36
+ })
37
+ .render(({ data }) => (
38
+ <ul>
39
+ {data.results.map((r, i) => <li key={i}>{r}</li>)}
40
+ </ul>
41
+ ));
42
+
43
+ // AI control tool
44
+ export const aiTool = aui
45
+ .tool('dom-click')
46
+ .input(z.object({ selector: z.string() }))
47
+ .execute(async ({ input }) => {
48
+ const element = document.querySelector(input.selector);
49
+ if (element instanceof HTMLElement) {
50
+ element.click();
51
+ return { success: true, selector: input.selector };
52
+ }
53
+ return { success: false, selector: input.selector };
54
+ });
55
+
56
+ // With middleware for auth/logging
57
+ export const protectedTool = aui
58
+ .tool('user-data')
59
+ .input(z.object({ userId: z.string() }))
60
+ .middleware(async ({ input, ctx, next }) => {
61
+ // Check auth
62
+ if (!ctx.user) throw new Error('Unauthorized');
63
+ // Log access
64
+ console.log(`User ${ctx.user.id} accessing ${input.userId}`);
65
+ return next();
66
+ })
67
+ .execute(async ({ input }) => ({
68
+ userId: input.userId,
69
+ data: 'sensitive data'
70
+ }));
71
+
72
+ // Chained/composed tools
73
+ export const composedTool = aui
74
+ .tool('weather-report')
75
+ .input(z.object({ city: z.string() }))
76
+ .execute(async ({ input }) => {
77
+ // Get weather
78
+ const weather = await simpleTool.run({ city: input.city });
79
+ // Get forecast
80
+ const forecast = ['Sunny', 'Cloudy', 'Rainy'][Math.floor(Math.random() * 3)];
81
+ return { ...weather, forecast };
82
+ })
83
+ .render(({ data }) => (
84
+ <div>
85
+ <h3>{data.city}</h3>
86
+ <p>Current: {data.temp}°</p>
87
+ <p>Forecast: {data.forecast}</p>
88
+ </div>
89
+ ));
90
+
91
+ // Tagged tools for discovery
92
+ export const notificationTool = aui
93
+ .tool('notify')
94
+ .tag('ui', 'notification')
95
+ .describe('Show a notification to the user')
96
+ .input(z.object({
97
+ message: z.string(),
98
+ type: z.enum(['info', 'success', 'error']).optional()
99
+ }))
100
+ .execute(async ({ input }) => {
101
+ // In real app, would show actual notification
102
+ console.log(`[${input.type || 'info'}] ${input.message}`);
103
+ return { shown: true };
104
+ });
105
+
106
+ // Streaming tool (for Vercel AI SDK)
107
+ export const streamingTool = aui
108
+ .tool('generate-text')
109
+ .input(z.object({ prompt: z.string() }))
110
+ .execute(async function* ({ input }) {
111
+ const words = input.prompt.split(' ');
112
+ for (const word of words) {
113
+ await new Promise(r => setTimeout(r, 100));
114
+ yield word + ' ';
115
+ }
116
+ });
117
+
118
+ // Batch processing tool
119
+ export const batchTool = aui
120
+ .tool('batch-process')
121
+ .input(z.object({ items: z.array(z.string()) }))
122
+ .execute(async ({ input }) => {
123
+ const results = await Promise.all(
124
+ input.items.map(async item => {
125
+ // Process each item
126
+ return { item, processed: item.toUpperCase() };
127
+ })
128
+ );
129
+ return { results };
130
+ });
131
+
132
+ // Error handling
133
+ export const errorHandlingTool = aui
134
+ .tool('safe-fetch')
135
+ .input(z.object({ url: z.string().url() }))
136
+ .execute(async ({ input }) => {
137
+ try {
138
+ const response = await fetch(input.url);
139
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
140
+ return { data: await response.json(), error: null };
141
+ } catch (error) {
142
+ return { data: null, error: error instanceof Error ? error.message : 'Unknown error' };
143
+ }
144
+ })
145
+ .render(({ data }) => (
146
+ <div>
147
+ {data.error ? (
148
+ <p style={{ color: 'red' }}>Error: {data.error}</p>
149
+ ) : (
150
+ <pre>{JSON.stringify(data.data, null, 2)}</pre>
151
+ )}
152
+ </div>
153
+ ));
@@ -0,0 +1,163 @@
1
+ // AUI Tool Examples
2
+ import aui, { z } from '../index';
3
+ import React from 'react';
4
+
5
+ // Simple weather tool - just 2 methods
6
+ export const weatherTool = aui
7
+ .tool('weather')
8
+ .input(z.object({ city: z.string() }))
9
+ .execute(async ({ input }) => ({
10
+ temp: Math.floor(Math.random() * 30) + 60,
11
+ city: input.city,
12
+ condition: 'Sunny',
13
+ humidity: 65
14
+ }))
15
+ .render(({ data }) => (
16
+ <div className="p-4 bg-blue-50 rounded-lg">
17
+ <h3 className="text-lg font-semibold">{data.city}</h3>
18
+ <p className="text-2xl font-bold">{data.temp}°F</p>
19
+ <p className="text-sm text-gray-600">{data.condition} • {data.humidity}% humidity</p>
20
+ </div>
21
+ ));
22
+
23
+ // Complex search tool - adds client optimization
24
+ export const searchTool = aui
25
+ .tool('search')
26
+ .input(z.object({ query: z.string() }))
27
+ .execute(async ({ input }) => {
28
+ // Simulate database search
29
+ await new Promise(r => setTimeout(r, 500));
30
+ return {
31
+ results: [
32
+ { id: 1, title: `Result for "${input.query}"`, score: 0.95, description: 'First matching result with high relevance' },
33
+ { id: 2, title: `Another result`, score: 0.87, description: 'Secondary result with good relevance' },
34
+ { id: 3, title: `Related content`, score: 0.72, description: 'Additional related information' }
35
+ ],
36
+ total: 3,
37
+ query: input.query
38
+ };
39
+ })
40
+ .clientExecute(async ({ input, ctx }) => {
41
+ // Client-side optimization with caching
42
+ const cacheKey = `search:${input.query}`;
43
+ const cached = ctx.cache.get(cacheKey);
44
+ if (cached) {
45
+ console.log(`Cache hit for query: ${input.query}`);
46
+ return cached;
47
+ }
48
+
49
+ const result = await ctx.fetch('/api/aui/execute', {
50
+ method: 'POST',
51
+ headers: { 'Content-Type': 'application/json' },
52
+ body: JSON.stringify({ tool: 'search', input })
53
+ }).then(r => r.json());
54
+
55
+ ctx.cache.set(cacheKey, result);
56
+ return result;
57
+ })
58
+ .render(({ data, loading, error }) => {
59
+ if (loading) return <div className="animate-pulse">Searching...</div>;
60
+ if (error) return <div className="text-red-500">Error: {error.message}</div>;
61
+ if (!data) return <div className="text-gray-400">No data</div>;
62
+
63
+ return (
64
+ <div className="space-y-3">
65
+ <p className="text-sm text-gray-600">Found {data.total} results for &quot;{data.query}&quot;</p>
66
+ {data.results.map((result: any) => (
67
+ <div key={result.id} className="p-3 bg-white border rounded-lg hover:shadow-md transition-shadow">
68
+ <h4 className="font-semibold">{result.title}</h4>
69
+ <p className="text-sm text-gray-600">{result.description}</p>
70
+ <span className="text-xs text-blue-600">Score: {result.score}</span>
71
+ </div>
72
+ ))}
73
+ </div>
74
+ );
75
+ });
76
+
77
+ // Calculator tool with render
78
+ export const calculatorTool = aui
79
+ .tool('calculator')
80
+ .input(z.object({
81
+ a: z.number(),
82
+ b: z.number(),
83
+ op: z.enum(['+', '-', '*', '/'])
84
+ }))
85
+ .execute(({ input }) => {
86
+ const ops = {
87
+ '+': (a: number, b: number) => a + b,
88
+ '-': (a: number, b: number) => a - b,
89
+ '*': (a: number, b: number) => a * b,
90
+ '/': (a: number, b: number) => a / b
91
+ };
92
+ return {
93
+ result: ops[input.op](input.a, input.b),
94
+ expression: `${input.a} ${input.op} ${input.b}`
95
+ };
96
+ })
97
+ .render(({ data }) => (
98
+ <div className="p-3 bg-gray-50 rounded-lg font-mono">
99
+ <span className="text-gray-600">{data?.expression || ''} =</span>
100
+ <span className="ml-2 text-xl font-bold">{data?.result || 0}</span>
101
+ </div>
102
+ ));
103
+
104
+ // Data fetcher tool with both server and client execution
105
+ export const dataFetcherTool = aui
106
+ .tool('dataFetcher')
107
+ .input(z.object({
108
+ endpoint: z.string(),
109
+ method: z.enum(['GET', 'POST']).default('GET'),
110
+ body: z.any().optional()
111
+ }))
112
+ .execute(async ({ input }) => {
113
+ // Server-side execution
114
+ const response = await fetch(input.endpoint, {
115
+ method: input.method,
116
+ headers: { 'Content-Type': 'application/json' },
117
+ body: input.body ? JSON.stringify(input.body) : undefined
118
+ });
119
+ return await response.json();
120
+ })
121
+ .clientExecute(async ({ input, ctx }) => {
122
+ // Client-side with request deduplication
123
+ const requestKey = `${input.method}:${input.endpoint}:${JSON.stringify(input.body)}`;
124
+
125
+ // Check if request is already in flight
126
+ const inflight = ctx.cache.get(`inflight:${requestKey}`);
127
+ if (inflight) return inflight;
128
+
129
+ // Check cache
130
+ const cached = ctx.cache.get(requestKey);
131
+ if (cached && input.method === 'GET') return cached;
132
+
133
+ // Make request
134
+ const promise = ctx.fetch(input.endpoint, {
135
+ method: input.method,
136
+ headers: { 'Content-Type': 'application/json' },
137
+ body: input.body ? JSON.stringify(input.body) : undefined
138
+ }).then(r => r.json());
139
+
140
+ // Store inflight request
141
+ ctx.cache.set(`inflight:${requestKey}`, promise);
142
+
143
+ const result = await promise;
144
+
145
+ // Clear inflight and cache result
146
+ ctx.cache.delete(`inflight:${requestKey}`);
147
+ if (input.method === 'GET') {
148
+ ctx.cache.set(requestKey, result);
149
+ }
150
+
151
+ return result;
152
+ })
153
+ .render(({ data, loading }) => {
154
+ if (loading) return <div className="animate-pulse">Fetching data...</div>;
155
+ return (
156
+ <pre className="p-3 bg-gray-900 text-green-400 rounded-lg overflow-auto">
157
+ {data ? JSON.stringify(data, null, 2) : 'No data'}
158
+ </pre>
159
+ );
160
+ });
161
+
162
+ // Export advanced tools
163
+ export * from '../tools/advanced-examples';
@@ -0,0 +1,91 @@
1
+ 'use client';
2
+
3
+ import React from 'react';
4
+ import aui from '../index';
5
+ import { z } from 'zod';
6
+
7
+ // Simple tool - just 2 methods
8
+ const weatherTool = aui
9
+ .tool('weather')
10
+ .input(z.object({ city: z.string() }))
11
+ .execute(async ({ input }) => ({ temp: 72, city: input.city }))
12
+ .render(({ data }) => <div>{data.city}: {data.temp}°</div>);
13
+
14
+ // Complex tool - adds client optimization
15
+ const searchTool = aui
16
+ .tool('search')
17
+ .input(z.object({ query: z.string() }))
18
+ .execute(async ({ input }) => {
19
+ // Server-side: database search
20
+ return { results: [`Result for ${input.query}`] };
21
+ })
22
+ .clientExecute(async ({ input, ctx }) => {
23
+ // Client-side: cache-first strategy
24
+ const cached = ctx.cache.get(input.query);
25
+ if (cached) return cached;
26
+
27
+ const result = await ctx.fetch('/api/tools/search', {
28
+ method: 'POST',
29
+ body: JSON.stringify(input)
30
+ }).then(r => r.json());
31
+
32
+ ctx.cache.set(input.query, result);
33
+ return result;
34
+ })
35
+ .render(({ data }) => (
36
+ <div>
37
+ <h3>Search Results</h3>
38
+ <ul>
39
+ {data.results?.map((item: string, i: number) => (
40
+ <li key={i}>{item}</li>
41
+ ))}
42
+ </ul>
43
+ </div>
44
+ ));
45
+
46
+ // Export tools for use in components
47
+ export { weatherTool, searchTool };
48
+
49
+ // Demo component
50
+ export function QuickDemo() {
51
+ const [weatherData, setWeatherData] = React.useState<any>(null);
52
+ const [searchData, setSearchData] = React.useState<any>(null);
53
+
54
+ const handleWeather = async () => {
55
+ const data = await weatherTool.run({ city: 'San Francisco' });
56
+ setWeatherData(data);
57
+ };
58
+
59
+ const handleSearch = async () => {
60
+ const data = await searchTool.run({ query: 'AI tools' });
61
+ setSearchData(data);
62
+ };
63
+
64
+ return (
65
+ <div className="p-4 space-y-4">
66
+ <h2 className="text-2xl font-bold">AUI Quick Demo</h2>
67
+
68
+ <div className="space-y-2">
69
+ <button
70
+ onClick={handleWeather}
71
+ className="px-4 py-2 bg-blue-500 text-white rounded"
72
+ >
73
+ Get Weather
74
+ </button>
75
+ {weatherData && weatherTool.renderer &&
76
+ weatherTool.renderer({ data: weatherData })}
77
+ </div>
78
+
79
+ <div className="space-y-2">
80
+ <button
81
+ onClick={handleSearch}
82
+ className="px-4 py-2 bg-green-500 text-white rounded"
83
+ >
84
+ Search
85
+ </button>
86
+ {searchData && searchTool.renderer &&
87
+ searchTool.renderer({ data: searchData })}
88
+ </div>
89
+ </div>
90
+ );
91
+ }
@@ -0,0 +1,71 @@
1
+ import React from 'react';
2
+ import aui from '../index';
3
+ import { z } from 'zod';
4
+
5
+ // Simple tool - just 2 methods (execute + render)
6
+ const simpleTool = aui
7
+ .tool('weather')
8
+ .input(z.object({ city: z.string() }))
9
+ .execute(async ({ input }) => ({ temp: 72, city: input.city }))
10
+ .render(({ data }) => <div>{data.city}: {data.temp}°</div>);
11
+
12
+ // Complex tool - adds client optimization
13
+ const complexTool = aui
14
+ .tool('search')
15
+ .input(z.object({ query: z.string() }))
16
+ .execute(async ({ input }) => {
17
+ // Server-side database search
18
+ const response = await fetch('/api/db/search', {
19
+ method: 'POST',
20
+ body: JSON.stringify(input)
21
+ });
22
+ return response.json();
23
+ })
24
+ .clientExecute(async ({ input, ctx }) => {
25
+ // Only when you need caching, offline, etc.
26
+ const cached = ctx.cache.get(input.query);
27
+ return cached || ctx.fetch('/api/tools/search', {
28
+ method: 'POST',
29
+ headers: { 'Content-Type': 'application/json' },
30
+ body: JSON.stringify(input)
31
+ }).then(r => r.json());
32
+ })
33
+ .render(({ data }) => (
34
+ <div className="space-y-2">
35
+ {data.map((item: any) => (
36
+ <div key={item.id} className="p-2 border rounded">
37
+ {item.title}
38
+ </div>
39
+ ))}
40
+ </div>
41
+ ));
42
+
43
+ // Tool with middleware for auth/logging
44
+ const protectedTool = aui
45
+ .tool('admin-action')
46
+ .input(z.object({ action: z.string() }))
47
+ .middleware(async ({ input, ctx, next }) => {
48
+ if (!ctx?.user) throw new Error('Auth required');
49
+ console.log(`User ${ctx.user.id} performing ${input.action}`);
50
+ return next();
51
+ })
52
+ .execute(async ({ input }) => ({
53
+ success: true,
54
+ action: input.action
55
+ }))
56
+ .render(({ data }) => (
57
+ <div className="text-green-600">
58
+ ✓ {data.action} completed
59
+ </div>
60
+ ));
61
+
62
+ // Minimal tool - execute only (no render needed)
63
+ const apiTool = aui
64
+ .tool('api-call')
65
+ .input(z.object({ endpoint: z.string() }))
66
+ .execute(async ({ input }) => {
67
+ const res = await fetch(input.endpoint);
68
+ return res.json();
69
+ });
70
+
71
+ export { simpleTool, complexTool, protectedTool, apiTool };
@@ -0,0 +1,160 @@
1
+ import React from 'react';
2
+ import aui from '../index';
3
+ import { z } from 'zod';
4
+
5
+ // Simple weather tool - just 2 methods
6
+ export const weatherTool = aui
7
+ .tool('weather')
8
+ .input(z.object({ city: z.string() }))
9
+ .execute(async ({ input }) => ({ temp: 72, city: input.city }))
10
+ .render(({ data }) => <div>{data.city}: {data.temp}°</div>);
11
+
12
+ // Complex search tool - adds client optimization
13
+ export const searchTool = aui
14
+ .tool('search')
15
+ .input(z.object({ query: z.string() }))
16
+ .execute(async ({ input }) => {
17
+ // Server-side: Mock database search
18
+ const results = [
19
+ { id: 1, title: `Result for "${input.query}"`, content: 'Lorem ipsum...' },
20
+ { id: 2, title: `Another match for "${input.query}"`, content: 'Dolor sit amet...' },
21
+ ];
22
+ return { query: input.query, results };
23
+ })
24
+ .clientExecute(async ({ input, ctx }) => {
25
+ // Client-side: Check cache first, then fetch
26
+ const cacheKey = `search:${input.query}`;
27
+ const cached = ctx.cache.get(cacheKey);
28
+ if (cached) return cached;
29
+
30
+ const response = await ctx.fetch('/api/aui/execute', {
31
+ method: 'POST',
32
+ headers: { 'Content-Type': 'application/json' },
33
+ body: JSON.stringify({ tool: 'search', input })
34
+ });
35
+ const data = await response.json();
36
+ ctx.cache.set(cacheKey, data);
37
+ return data;
38
+ })
39
+ .render(({ data }) => (
40
+ <div className="search-results">
41
+ <h3>Search Results for &quot;{data.query}&quot;</h3>
42
+ {data.results.map((result: any) => (
43
+ <div key={result.id} className="result-item">
44
+ <h4>{result.title}</h4>
45
+ <p>{result.content}</p>
46
+ </div>
47
+ ))}
48
+ </div>
49
+ ));
50
+
51
+ // Calculator tool - demonstrates middleware
52
+ export const calculatorTool = aui
53
+ .tool('calculator')
54
+ .input(z.object({
55
+ operation: z.enum(['add', 'subtract', 'multiply', 'divide']),
56
+ a: z.number(),
57
+ b: z.number()
58
+ }))
59
+ .middleware(async ({ input, next }) => {
60
+ console.log(`Calculating: ${input.a} ${input.operation} ${input.b}`);
61
+ const result = await next();
62
+ console.log(`Result: ${result}`);
63
+ return result;
64
+ })
65
+ .execute(({ input }) => {
66
+ const { operation, a, b } = input;
67
+ switch (operation) {
68
+ case 'add': return a + b;
69
+ case 'subtract': return a - b;
70
+ case 'multiply': return a * b;
71
+ case 'divide': return b !== 0 ? a / b : NaN;
72
+ default: throw new Error(`Unknown operation: ${operation}`);
73
+ }
74
+ })
75
+ .render(({ data, input }) => (
76
+ <div className="calculator-result">
77
+ {input?.a} {input?.operation} {input?.b} = {data}
78
+ </div>
79
+ ));
80
+
81
+ // Form submission tool
82
+ export const formTool = aui
83
+ .tool('submitForm')
84
+ .input(z.object({
85
+ name: z.string().min(1),
86
+ email: z.string().email(),
87
+ message: z.string().optional()
88
+ }))
89
+ .execute(async ({ input }) => {
90
+ // Simulate form submission
91
+ await new Promise(resolve => setTimeout(resolve, 500));
92
+ return { success: true, id: Math.random().toString(36).substr(2, 9), ...input };
93
+ })
94
+ .render(({ data, loading, error }) => {
95
+ if (loading) return <div>Submitting...</div>;
96
+ if (error) return <div className="error">Error: {error.message}</div>;
97
+ return (
98
+ <div className="form-success">
99
+ ✅ Form submitted successfully!
100
+ <p>Submission ID: {data.id}</p>
101
+ <p>Name: {data.name}</p>
102
+ <p>Email: {data.email}</p>
103
+ {data.message && <p>Message: {data.message}</p>}
104
+ </div>
105
+ );
106
+ });
107
+
108
+ // Navigation tool - AI can control page navigation
109
+ export const navigationTool = aui
110
+ .tool('navigate')
111
+ .input(z.object({
112
+ path: z.string(),
113
+ params: z.record(z.string()).optional()
114
+ }))
115
+ .clientExecute(async ({ input }) => {
116
+ const url = new URL(input.path, window.location.origin);
117
+ if (input.params) {
118
+ Object.entries(input.params).forEach(([key, value]) => {
119
+ url.searchParams.set(key, value);
120
+ });
121
+ }
122
+ window.history.pushState({}, '', url.toString());
123
+ return { navigated: true, url: url.toString() };
124
+ })
125
+ .render(({ data }) => (
126
+ <div>Navigated to: {data.url}</div>
127
+ ));
128
+
129
+ // State management tool - AI can control application state
130
+ export const stateTool = aui
131
+ .tool('setState')
132
+ .input(z.object({
133
+ key: z.string(),
134
+ value: z.any(),
135
+ action: z.enum(['set', 'get', 'delete']).default('set')
136
+ }))
137
+ .clientExecute(({ input, ctx }) => {
138
+ const stateMap = ctx.cache.get('appState') || new Map();
139
+
140
+ switch (input.action) {
141
+ case 'get':
142
+ return { key: input.key, value: stateMap.get(input.key) };
143
+ case 'delete':
144
+ stateMap.delete(input.key);
145
+ ctx.cache.set('appState', stateMap);
146
+ return { key: input.key, deleted: true };
147
+ case 'set':
148
+ default:
149
+ stateMap.set(input.key, input.value);
150
+ ctx.cache.set('appState', stateMap);
151
+ return { key: input.key, value: input.value, updated: true };
152
+ }
153
+ })
154
+ .render(({ data }) => (
155
+ <div className="state-update">
156
+ {data.deleted ? `Deleted: ${data.key}` :
157
+ data.updated ? `Updated: ${data.key} = ${JSON.stringify(data.value)}` :
158
+ `Retrieved: ${data.key} = ${JSON.stringify(data.value)}`}
159
+ </div>
160
+ ));