@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Lyndon Leong
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # Better UI - AUI (Assistant-UI) System
2
+
3
+ A concise and elegant tool system for Next.js that enables AI assistants to control both frontend and backend through a fluent API.
4
+
5
+ ## 🚀 Quick Start
6
+
7
+ ```tsx
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 }) => db.search(input.query))
20
+ .clientExecute(async ({ input, ctx }) => {
21
+ // Only when you need caching, offline, etc.
22
+ const cached = ctx.cache.get(input.query);
23
+ return cached || ctx.fetch('/api/tools/search', { body: input });
24
+ })
25
+ .render(({ data }) => <SearchResults results={data} />);
26
+ ```
27
+
28
+ ## ✨ Features
29
+
30
+ - **Fluent API**: Chain methods for clean, readable tool definitions
31
+ - **Type Safety**: Full TypeScript support with Zod schemas
32
+ - **Minimal Boilerplate**: Only `input()` and `execute()` are required
33
+ - **Dual Execution**: Server-side execution with optional client-side optimization
34
+ - **React Integration**: Seamless rendering of tool results
35
+ - **AI-Ready**: Designed for AI assistants to control UI/backend
36
+
37
+ ## 🏗️ Architecture
38
+
39
+ ```
40
+ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐
41
+ │ Client │────▶│ AUI System │────▶│ Server │
42
+ │ Component │ │ │ │ Handler │
43
+ └─────────────┘ └──────────────┘ └─────────────┘
44
+ │ │ │
45
+ ▼ ▼ ▼
46
+ ToolRenderer ClientExecutor ToolExecutor
47
+ (optional) (server-side)
48
+ ```
49
+
50
+ ## 📦 Installation
51
+
52
+ ```bash
53
+ npm install
54
+ npm run dev
55
+ ```
56
+
57
+ ## 🛠️ API Reference
58
+
59
+ ### Tool Builder
60
+
61
+ - `.tool(name)` - Create a new tool builder
62
+ - `.input(schema)` - Define input validation with Zod
63
+ - `.execute(handler)` - Server-side execution logic
64
+ - `.clientExecute(handler)` - Optional client-side execution
65
+ - `.render(component)` - React component for rendering results
66
+ - `.description(text)` - Optional tool description
67
+ - Returns a built tool object ready to use (no build step needed)
68
+
69
+ ### React Components
70
+
71
+ ```tsx
72
+ import { ToolExecutorProvider, ToolRenderer, useToolExecutor } from '@/lib/aui/client';
73
+
74
+ // Provider setup
75
+ <ToolExecutorProvider tools={[weatherTool, searchTool]}>
76
+ <App />
77
+ </ToolExecutorProvider>
78
+
79
+ // Render a tool result
80
+ <ToolRenderer toolCall={toolCall} tool={weatherTool} />
81
+
82
+ // Hook usage
83
+ const executor = useToolExecutor();
84
+ const result = await executor.execute(toolCall);
85
+ ```
86
+
87
+ ## 🔧 Usage Examples
88
+
89
+ ### Basic Tool
90
+ ```tsx
91
+ const weatherTool = aui
92
+ .tool('weather')
93
+ .input(z.object({ city: z.string() }))
94
+ .execute(async ({ input }) => {
95
+ const response = await fetch(`/api/weather?city=${input.city}`);
96
+ return response.json();
97
+ })
98
+ .render(({ data }) => (
99
+ <div className="weather-card">
100
+ <h3>{data.city}</h3>
101
+ <p>{data.temp}°F</p>
102
+ </div>
103
+ ));
104
+ ```
105
+
106
+ ### Tool with Client Optimization
107
+ ```tsx
108
+ const searchTool = aui
109
+ .tool('search')
110
+ .input(z.object({ query: z.string() }))
111
+ .execute(async ({ input }) => {
112
+ return await database.search(input.query);
113
+ })
114
+ .clientExecute(async ({ input, ctx }) => {
115
+ // Client-side caching and offline support
116
+ const cached = ctx.cache.get(input.query);
117
+ if (cached) return cached;
118
+
119
+ const result = await ctx.fetch('/api/aui', {
120
+ method: 'POST',
121
+ body: JSON.stringify({
122
+ toolCall: { toolName: 'search', input }
123
+ })
124
+ });
125
+
126
+ ctx.cache.set(input.query, result);
127
+ return result;
128
+ })
129
+ .render(({ data }) => <SearchResults results={data} />);
130
+ ```
131
+
132
+ ## 🗂️ Project Structure
133
+
134
+ ```
135
+ better-ui/
136
+ ├── app/ # Next.js app directory
137
+ │ ├── api/ # API routes
138
+ │ └── aui-demo/ # Demo pages
139
+ ├── lib/aui/ # AUI system core
140
+ │ ├── core/ # Core builder and registry
141
+ │ ├── client/ # Client-side execution
142
+ │ ├── server/ # Server-side execution
143
+ │ ├── tools/ # Example tools
144
+ │ └── types/ # TypeScript definitions
145
+ ├── examples/ # Usage examples
146
+ └── agent/ # Development metadata
147
+ ```
148
+
149
+ ## 🧪 Testing
150
+
151
+ ```bash
152
+ npm test
153
+ npm run type-check
154
+ npm run lint
155
+ ```
156
+
157
+ ## 🚀 Development
158
+
159
+ ```bash
160
+ # Start development server
161
+ npm run dev
162
+
163
+ # Build for production
164
+ npm run build
165
+
166
+ # Start production server
167
+ npm start
168
+ ```
169
+
170
+ ## 📚 Documentation
171
+
172
+ - [AUI System Overview](AUI.md) - Detailed system documentation
173
+ - [Examples](./examples/) - Complete usage examples
174
+ - [API Reference](./lib/aui/README.md) - Core API documentation
175
+
176
+ ## 🤝 Contributing
177
+
178
+ 1. Fork the repository
179
+ 2. Create a feature branch
180
+ 3. Make your changes
181
+ 4. Add tests
182
+ 5. Submit a pull request
183
+
184
+ ## 📄 License
185
+
186
+ This project is private and proprietary.
187
+
188
+ ---
189
+
190
+ Built with ❤️ using Next.js, TypeScript, and Zod.
@@ -0,0 +1,136 @@
1
+ # AUI (Assistant-UI) System
2
+
3
+ A concise, type-safe tool system for AI assistants to control frontend and backend operations in Next.js/Vercel applications.
4
+
5
+ ## Quick Start
6
+
7
+ ```tsx
8
+ import aui from '@/lib/aui';
9
+ import { z } from 'zod';
10
+
11
+ // Simple tool - just 2 methods
12
+ const simpleTool = aui
13
+ .tool('weather')
14
+ .input(z.object({ city: z.string() }))
15
+ .execute(async ({ input }) => ({ temp: 72, city: input.city }))
16
+ .render(({ data }) => <div>{data.city}: {data.temp}°</div>);
17
+
18
+ // Complex tool - adds client optimization
19
+ const complexTool = aui
20
+ .tool('search')
21
+ .input(z.object({ query: z.string() }))
22
+ .execute(async ({ input }) => db.search(input.query))
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', { body: input });
27
+ })
28
+ .render(({ data }) => <SearchResults results={data} />);
29
+ ```
30
+
31
+ ## Core Features
32
+
33
+ - **Concise API**: Define tools in 2-4 method calls
34
+ - **Type Safety**: Full TypeScript support with Zod validation
35
+ - **Dual Execution**: Run on server (default) or client (optimized)
36
+ - **React Integration**: Built-in rendering and hooks
37
+ - **Context Management**: Caching, sessions, and state
38
+ - **AI-Ready**: Designed for AI assistant control
39
+
40
+ ## API Methods
41
+
42
+ ### Core Methods
43
+ - `.tool(name)` - Create a new tool
44
+ - `.input(schema)` - Define input validation with Zod
45
+ - `.execute(handler)` - Server-side execution logic
46
+ - `.render(component)` - React component for rendering results
47
+
48
+ ### Optional Methods
49
+ - `.clientExecute(handler)` - Client-side execution with caching
50
+ - `.middleware(fn)` - Add middleware for auth, logging, etc.
51
+ - `.describe(text)` - Add description for documentation
52
+ - `.tag(...tags)` - Add tags for organization
53
+
54
+ ## Examples
55
+
56
+ See `/lib/aui/examples/` for complete examples including:
57
+ - Weather tool (simple)
58
+ - Search tool (with caching)
59
+ - Calculator tool (with validation)
60
+ - Form tool (with middleware)
61
+ - Analytics tool (complex visualization)
62
+
63
+ ## Using Tools in React
64
+
65
+ ```tsx
66
+ import { useAUITool, AUIProvider } from '@/lib/aui';
67
+
68
+ function MyComponent() {
69
+ const { execute, data, loading, error } = useAUITool(weatherTool);
70
+
71
+ return (
72
+ <div>
73
+ <button onClick={() => execute({ city: 'NYC' })}>
74
+ Get Weather
75
+ </button>
76
+ {loading && <div>Loading...</div>}
77
+ {data && weatherTool.renderer({ data })}
78
+ </div>
79
+ );
80
+ }
81
+
82
+ // Wrap your app with AUIProvider
83
+ export default function App() {
84
+ return (
85
+ <AUIProvider>
86
+ <MyComponent />
87
+ </AUIProvider>
88
+ );
89
+ }
90
+ ```
91
+
92
+ ## AI Control Example
93
+
94
+ Enable AI assistants to control both frontend and backend:
95
+
96
+ ```tsx
97
+ const databaseTool = aui
98
+ .tool('database')
99
+ .input(z.object({
100
+ table: z.string(),
101
+ operation: z.enum(['select', 'insert', 'update', 'delete']),
102
+ conditions: z.record(z.any()).optional()
103
+ }))
104
+ .execute(async ({ input }) => {
105
+ // Server-side database operations
106
+ return await db[input.operation](input.table, input.conditions);
107
+ })
108
+ .clientExecute(async ({ input, ctx }) => {
109
+ // Client-side optimistic updates
110
+ if (input.operation === 'select') {
111
+ const cached = ctx.cache.get(`${input.table}:${input.operation}`);
112
+ if (cached) return cached;
113
+ }
114
+ return ctx.fetch('/api/database', { body: input });
115
+ });
116
+ ```
117
+
118
+ ## AI Control Examples
119
+
120
+ The system includes comprehensive examples for AI control in `/lib/aui/examples/ai-control-full.tsx`:
121
+
122
+ - **Database Operations**: Query and manipulate data
123
+ - **UI Control**: Manage modals, navigation, themes
124
+ - **File System**: Read/write files (server-side)
125
+ - **API Integration**: Call external APIs with CORS proxy
126
+ - **Real-time Streams**: WebSocket/SSE connections
127
+ - **Form Generation**: Dynamic form creation
128
+ - **Analytics**: Event tracking and analysis
129
+
130
+ ## Testing
131
+
132
+ ```bash
133
+ npm test -- --testPathPattern=aui
134
+ ```
135
+
136
+ All 63 tests passing ✅
@@ -0,0 +1,251 @@
1
+ import { describe, it, expect, beforeEach } from '@jest/globals';
2
+ import aui, { z } from '../index';
3
+ import { AIControlledTool, createAITool, aiControlSystem } from '../ai-control';
4
+ import { clientControlSystem } from '../client-control';
5
+
6
+ describe('AUI Complete System Tests', () => {
7
+ beforeEach(() => {
8
+ aui.clear();
9
+ aiControlSystem.clear();
10
+ });
11
+
12
+ describe('Simple Tool Pattern', () => {
13
+ it('should create a simple tool with execute and render', async () => {
14
+ const simpleTool = aui
15
+ .tool('weather')
16
+ .input(z.object({ city: z.string() }))
17
+ .execute(async ({ input }) => ({ temp: 72, city: input.city }))
18
+ .render(({ data }) => `${data.city}: ${data.temp}°` as any);
19
+
20
+ expect(simpleTool.name).toBe('weather');
21
+
22
+ const result = await simpleTool.run({ city: 'New York' });
23
+ expect(result).toEqual({ temp: 72, city: 'New York' });
24
+ });
25
+
26
+ it('should validate input schema', async () => {
27
+ const tool = aui
28
+ .tool('validated')
29
+ .input(z.object({
30
+ required: z.string(),
31
+ optional: z.number().optional()
32
+ }))
33
+ .execute(async ({ input }) => input);
34
+
35
+ await expect(tool.run({ required: 'test' })).resolves.toEqual({ required: 'test' });
36
+ await expect(tool.run({ missing: 'field' } as any)).rejects.toThrow();
37
+ });
38
+ });
39
+
40
+ describe('Complex Tool Pattern', () => {
41
+ it('should support client and server execution', async () => {
42
+ const complexTool = aui
43
+ .tool('search')
44
+ .input(z.object({ query: z.string() }))
45
+ .execute(async ({ input }) => ({
46
+ results: [`server: ${input.query}`]
47
+ }))
48
+ .clientExecute(async ({ input, ctx }) => {
49
+ const cached = ctx.cache.get(input.query);
50
+ if (cached) return cached;
51
+
52
+ const result = { results: [`client: ${input.query}`] };
53
+ ctx.cache.set(input.query, result);
54
+ return result;
55
+ });
56
+
57
+ // Server execution
58
+ const serverResult = await complexTool.run(
59
+ { query: 'test' },
60
+ { isServer: true, cache: new Map(), fetch: fetch }
61
+ );
62
+ expect(serverResult.results[0]).toContain('server');
63
+
64
+ // Client execution
65
+ const clientResult = await complexTool.run(
66
+ { query: 'test' },
67
+ { isServer: false, cache: new Map(), fetch: fetch }
68
+ );
69
+ expect(clientResult.results[0]).toContain('client');
70
+ });
71
+
72
+ it('should support middleware', async () => {
73
+ const middlewareTool = aui
74
+ .tool('with-middleware')
75
+ .input(z.object({ value: z.number() }))
76
+ .execute(async ({ input }) => ({ result: input.value }))
77
+ .middleware(async ({ input, next }) => {
78
+ input.value = input.value * 2;
79
+ const result = await next();
80
+ result.result = result.result + 10;
81
+ return result;
82
+ });
83
+
84
+ const result = await middlewareTool.run({ value: 5 });
85
+ expect(result).toEqual({ result: 20 }); // (5 * 2) + 10
86
+ });
87
+ });
88
+
89
+ describe('AI Control System', () => {
90
+ it('should create AI-controlled tools with permissions', () => {
91
+ const aiTool = createAITool('ai-tool', {
92
+ permissions: {
93
+ allowClientExecution: true,
94
+ allowServerExecution: false
95
+ }
96
+ })
97
+ .input(z.object({ action: z.string() }))
98
+ .execute(async ({ input }) => ({ executed: input.action }));
99
+
100
+ expect(aiTool).toBeInstanceOf(AIControlledTool);
101
+ expect(aiTool.name).toBe('ai-tool');
102
+ });
103
+
104
+ it('should enforce rate limiting', async () => {
105
+ const rateLimitedTool = createAITool('rate-limited', {
106
+ rateLimit: {
107
+ requestsPerMinute: 2
108
+ },
109
+ audit: true // Enable audit to track execution for rate limiting
110
+ })
111
+ .input(z.object({ id: z.number() }))
112
+ .execute(async ({ input }) => ({ id: input.id }));
113
+
114
+ // First two requests should succeed
115
+ await expect(rateLimitedTool.run({ id: 1 })).resolves.toEqual({ id: 1 });
116
+ await expect(rateLimitedTool.run({ id: 2 })).resolves.toEqual({ id: 2 });
117
+
118
+ // Third request should fail
119
+ await expect(rateLimitedTool.run({ id: 3 })).rejects.toThrow('Rate limit exceeded');
120
+ });
121
+
122
+ it('should track execution with audit', async () => {
123
+ const auditedTool = createAITool('audited', { audit: true })
124
+ .input(z.object({ action: z.string() }))
125
+ .execute(async ({ input }) => ({ result: input.action }));
126
+
127
+ await auditedTool.run({ action: 'test1' });
128
+ await auditedTool.run({ action: 'test2' });
129
+
130
+ const log = auditedTool.getExecutionLog();
131
+ expect(log).toHaveLength(2);
132
+ expect(log[0].input).toEqual({ action: 'test1' });
133
+ expect(log[1].input).toEqual({ action: 'test2' });
134
+ });
135
+ });
136
+
137
+ describe('Tool Registry', () => {
138
+ it('should register and retrieve tools', () => {
139
+ const tool1 = aui.tool('tool1')
140
+ .input(z.object({ x: z.number() }))
141
+ .execute(async ({ input }) => input);
142
+
143
+ const tool2 = aui.tool('tool2')
144
+ .input(z.object({ y: z.string() }))
145
+ .execute(async ({ input }) => input);
146
+
147
+ expect(aui.has('tool1')).toBe(true);
148
+ expect(aui.has('tool2')).toBe(true);
149
+ expect(aui.getToolNames()).toEqual(['tool1', 'tool2']);
150
+ });
151
+
152
+ it('should support tool tags and discovery', () => {
153
+ const apiTool = aui.tool('api')
154
+ .tag('backend', 'api', 'rest')
155
+ .execute(async () => ({ success: true }));
156
+
157
+ const uiTool = aui.tool('ui')
158
+ .tag('frontend', 'ui', 'dom')
159
+ .execute(async () => ({ rendered: true }));
160
+
161
+ expect(aui.findByTag('backend')).toContain(apiTool);
162
+ expect(aui.findByTag('frontend')).toContain(uiTool);
163
+ expect(aui.findByTags('backend', 'api')).toContain(apiTool);
164
+ });
165
+ });
166
+
167
+ describe('Tool Execution', () => {
168
+ it('should execute tools through AUI instance', async () => {
169
+ aui.tool('executor')
170
+ .input(z.object({ value: z.number() }))
171
+ .execute(async ({ input }) => ({ doubled: input.value * 2 }));
172
+
173
+ const result = await aui.execute('executor', { value: 5 });
174
+ expect(result).toEqual({ doubled: 10 });
175
+ });
176
+
177
+ it('should handle execution errors', async () => {
178
+ aui.tool('error-tool')
179
+ .execute(async () => {
180
+ throw new Error('Execution failed');
181
+ });
182
+
183
+ await expect(aui.execute('error-tool', {})).rejects.toThrow('Execution failed');
184
+ });
185
+ });
186
+
187
+ describe('Client Control System', () => {
188
+ it('should list available client tools', () => {
189
+ const tools = clientControlSystem.listClientTools();
190
+
191
+ expect(tools).toContainEqual(
192
+ expect.objectContaining({
193
+ name: 'client-dom',
194
+ description: 'Manipulate DOM elements on the client'
195
+ })
196
+ );
197
+
198
+ expect(tools).toContainEqual(
199
+ expect.objectContaining({
200
+ name: 'client-forms',
201
+ description: 'Control and interact with forms'
202
+ })
203
+ );
204
+ });
205
+ });
206
+
207
+ describe('Tool Serialization', () => {
208
+ it('should serialize tool configuration', () => {
209
+ const tool = aui.tool('serializable')
210
+ .describe('A test tool')
211
+ .tag('test', 'demo')
212
+ .input(z.object({ x: z.number() }))
213
+ .execute(async ({ input }) => input)
214
+ .clientExecute(async ({ input }) => input)
215
+ .render(() => null as any);
216
+
217
+ const json = tool.toJSON();
218
+
219
+ expect(json).toEqual({
220
+ name: 'serializable',
221
+ description: 'A test tool',
222
+ tags: ['test', 'demo'],
223
+ hasInput: true,
224
+ hasExecute: true,
225
+ hasClientExecute: true,
226
+ hasRender: true,
227
+ hasMiddleware: false
228
+ });
229
+ });
230
+ });
231
+
232
+ describe('Context Management', () => {
233
+ it('should create and use context correctly', async () => {
234
+ const contextTool = aui.tool('context-test')
235
+ .execute(async ({ ctx }) => ({
236
+ isServer: ctx?.isServer,
237
+ hasCache: ctx?.cache instanceof Map,
238
+ hasFetch: typeof ctx?.fetch === 'function'
239
+ }));
240
+
241
+ const result = await contextTool.run({}, aui.createContext({
242
+ isServer: true,
243
+ user: { id: 1 }
244
+ }));
245
+
246
+ expect(result.isServer).toBe(true);
247
+ expect(result.hasCache).toBe(true);
248
+ expect(result.hasFetch).toBe(true);
249
+ });
250
+ });
251
+ });