@agentforge-ai/cli 0.3.2 → 0.4.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 (89) hide show
  1. package/dist/default/.env.example +46 -6
  2. package/dist/default/README.md +89 -9
  3. package/dist/default/convex/schema.ts +248 -4
  4. package/dist/default/dashboard/app/components/DashboardLayout.tsx +245 -0
  5. package/dist/default/dashboard/app/components/ui/badge.tsx +26 -0
  6. package/dist/default/dashboard/app/components/ui/button.tsx +41 -0
  7. package/dist/default/dashboard/app/components/ui/card.tsx +44 -0
  8. package/dist/default/dashboard/app/components/ui/dialog.tsx +66 -0
  9. package/dist/default/dashboard/app/components/ui/input.tsx +21 -0
  10. package/dist/default/dashboard/app/components/ui/label.tsx +18 -0
  11. package/dist/default/dashboard/app/components/ui/select.tsx +75 -0
  12. package/dist/default/dashboard/app/components/ui/sheet.tsx +73 -0
  13. package/dist/default/dashboard/app/components/ui/switch.tsx +34 -0
  14. package/dist/default/dashboard/app/components/ui/table.tsx +60 -0
  15. package/dist/default/dashboard/app/components/ui/tabs.tsx +50 -0
  16. package/dist/default/dashboard/app/components/ui/tooltip.tsx +23 -0
  17. package/dist/default/dashboard/app/lib/utils.ts +6 -0
  18. package/dist/default/dashboard/app/main.tsx +35 -0
  19. package/dist/default/dashboard/app/routeTree.gen.ts +352 -0
  20. package/dist/default/dashboard/app/routes/__root.tsx +10 -0
  21. package/dist/default/dashboard/app/routes/agents.tsx +255 -0
  22. package/dist/default/dashboard/app/routes/chat.tsx +427 -0
  23. package/dist/default/dashboard/app/routes/connections.tsx +413 -0
  24. package/dist/default/dashboard/app/routes/cron.tsx +322 -0
  25. package/dist/default/dashboard/app/routes/files.tsx +203 -0
  26. package/dist/default/dashboard/app/routes/index.tsx +141 -0
  27. package/dist/default/dashboard/app/routes/projects.tsx +254 -0
  28. package/dist/default/dashboard/app/routes/sessions.tsx +272 -0
  29. package/dist/default/dashboard/app/routes/settings.tsx +583 -0
  30. package/dist/default/dashboard/app/routes/skills.tsx +252 -0
  31. package/dist/default/dashboard/app/routes/usage.tsx +181 -0
  32. package/dist/default/dashboard/app/styles/globals.css +93 -0
  33. package/dist/default/dashboard/index.html +13 -0
  34. package/dist/default/dashboard/package.json +36 -0
  35. package/dist/default/dashboard/postcss.config.js +6 -0
  36. package/dist/default/dashboard/tailwind.config.js +50 -0
  37. package/dist/default/dashboard/tsconfig.json +24 -0
  38. package/dist/default/dashboard/vite.config.ts +16 -0
  39. package/dist/default/package.json +8 -3
  40. package/dist/default/skills/skill-creator/SKILL.md +270 -0
  41. package/dist/default/skills/skill-creator/config.json +11 -0
  42. package/dist/default/skills/skill-creator/index.ts +392 -0
  43. package/dist/default/src/agent.ts +85 -5
  44. package/dist/index.js +1574 -10
  45. package/dist/index.js.map +1 -1
  46. package/package.json +2 -1
  47. package/templates/default/.env.example +46 -6
  48. package/templates/default/README.md +89 -9
  49. package/templates/default/convex/schema.ts +248 -4
  50. package/templates/default/dashboard/app/components/DashboardLayout.tsx +245 -0
  51. package/templates/default/dashboard/app/components/ui/badge.tsx +26 -0
  52. package/templates/default/dashboard/app/components/ui/button.tsx +41 -0
  53. package/templates/default/dashboard/app/components/ui/card.tsx +44 -0
  54. package/templates/default/dashboard/app/components/ui/dialog.tsx +66 -0
  55. package/templates/default/dashboard/app/components/ui/input.tsx +21 -0
  56. package/templates/default/dashboard/app/components/ui/label.tsx +18 -0
  57. package/templates/default/dashboard/app/components/ui/select.tsx +75 -0
  58. package/templates/default/dashboard/app/components/ui/sheet.tsx +73 -0
  59. package/templates/default/dashboard/app/components/ui/switch.tsx +34 -0
  60. package/templates/default/dashboard/app/components/ui/table.tsx +60 -0
  61. package/templates/default/dashboard/app/components/ui/tabs.tsx +50 -0
  62. package/templates/default/dashboard/app/components/ui/tooltip.tsx +23 -0
  63. package/templates/default/dashboard/app/lib/utils.ts +6 -0
  64. package/templates/default/dashboard/app/main.tsx +35 -0
  65. package/templates/default/dashboard/app/routeTree.gen.ts +352 -0
  66. package/templates/default/dashboard/app/routes/__root.tsx +10 -0
  67. package/templates/default/dashboard/app/routes/agents.tsx +255 -0
  68. package/templates/default/dashboard/app/routes/chat.tsx +427 -0
  69. package/templates/default/dashboard/app/routes/connections.tsx +413 -0
  70. package/templates/default/dashboard/app/routes/cron.tsx +322 -0
  71. package/templates/default/dashboard/app/routes/files.tsx +203 -0
  72. package/templates/default/dashboard/app/routes/index.tsx +141 -0
  73. package/templates/default/dashboard/app/routes/projects.tsx +254 -0
  74. package/templates/default/dashboard/app/routes/sessions.tsx +272 -0
  75. package/templates/default/dashboard/app/routes/settings.tsx +583 -0
  76. package/templates/default/dashboard/app/routes/skills.tsx +252 -0
  77. package/templates/default/dashboard/app/routes/usage.tsx +181 -0
  78. package/templates/default/dashboard/app/styles/globals.css +93 -0
  79. package/templates/default/dashboard/index.html +13 -0
  80. package/templates/default/dashboard/package.json +36 -0
  81. package/templates/default/dashboard/postcss.config.js +6 -0
  82. package/templates/default/dashboard/tailwind.config.js +50 -0
  83. package/templates/default/dashboard/tsconfig.json +24 -0
  84. package/templates/default/dashboard/vite.config.ts +16 -0
  85. package/templates/default/package.json +8 -3
  86. package/templates/default/skills/skill-creator/SKILL.md +270 -0
  87. package/templates/default/skills/skill-creator/config.json +11 -0
  88. package/templates/default/skills/skill-creator/index.ts +392 -0
  89. package/templates/default/src/agent.ts +85 -5
@@ -0,0 +1,352 @@
1
+ /* eslint-disable */
2
+
3
+ // @ts-nocheck
4
+
5
+ // noinspection JSUnusedGlobalSymbols
6
+
7
+ // This file was automatically generated by TanStack Router.
8
+ // You should NOT make any changes in this file as it will be overwritten.
9
+ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
10
+
11
+ // Import Routes
12
+
13
+ import { Route as rootRoute } from './routes/__root'
14
+ import { Route as UsageImport } from './routes/usage'
15
+ import { Route as SkillsImport } from './routes/skills'
16
+ import { Route as SettingsImport } from './routes/settings'
17
+ import { Route as SessionsImport } from './routes/sessions'
18
+ import { Route as ProjectsImport } from './routes/projects'
19
+ import { Route as FilesImport } from './routes/files'
20
+ import { Route as CronImport } from './routes/cron'
21
+ import { Route as ConnectionsImport } from './routes/connections'
22
+ import { Route as ChatImport } from './routes/chat'
23
+ import { Route as AgentsImport } from './routes/agents'
24
+ import { Route as IndexImport } from './routes/index'
25
+
26
+ // Create/Update Routes
27
+
28
+ const UsageRoute = UsageImport.update({
29
+ id: '/usage',
30
+ path: '/usage',
31
+ getParentRoute: () => rootRoute,
32
+ } as any)
33
+
34
+ const SkillsRoute = SkillsImport.update({
35
+ id: '/skills',
36
+ path: '/skills',
37
+ getParentRoute: () => rootRoute,
38
+ } as any)
39
+
40
+ const SettingsRoute = SettingsImport.update({
41
+ id: '/settings',
42
+ path: '/settings',
43
+ getParentRoute: () => rootRoute,
44
+ } as any)
45
+
46
+ const SessionsRoute = SessionsImport.update({
47
+ id: '/sessions',
48
+ path: '/sessions',
49
+ getParentRoute: () => rootRoute,
50
+ } as any)
51
+
52
+ const ProjectsRoute = ProjectsImport.update({
53
+ id: '/projects',
54
+ path: '/projects',
55
+ getParentRoute: () => rootRoute,
56
+ } as any)
57
+
58
+ const FilesRoute = FilesImport.update({
59
+ id: '/files',
60
+ path: '/files',
61
+ getParentRoute: () => rootRoute,
62
+ } as any)
63
+
64
+ const CronRoute = CronImport.update({
65
+ id: '/cron',
66
+ path: '/cron',
67
+ getParentRoute: () => rootRoute,
68
+ } as any)
69
+
70
+ const ConnectionsRoute = ConnectionsImport.update({
71
+ id: '/connections',
72
+ path: '/connections',
73
+ getParentRoute: () => rootRoute,
74
+ } as any)
75
+
76
+ const ChatRoute = ChatImport.update({
77
+ id: '/chat',
78
+ path: '/chat',
79
+ getParentRoute: () => rootRoute,
80
+ } as any)
81
+
82
+ const AgentsRoute = AgentsImport.update({
83
+ id: '/agents',
84
+ path: '/agents',
85
+ getParentRoute: () => rootRoute,
86
+ } as any)
87
+
88
+ const IndexRoute = IndexImport.update({
89
+ id: '/',
90
+ path: '/',
91
+ getParentRoute: () => rootRoute,
92
+ } as any)
93
+
94
+ // Populate the FileRoutesByPath interface
95
+
96
+ declare module '@tanstack/react-router' {
97
+ interface FileRoutesByPath {
98
+ '/': {
99
+ id: '/'
100
+ path: '/'
101
+ fullPath: '/'
102
+ preLoaderRoute: typeof IndexImport
103
+ parentRoute: typeof rootRoute
104
+ }
105
+ '/agents': {
106
+ id: '/agents'
107
+ path: '/agents'
108
+ fullPath: '/agents'
109
+ preLoaderRoute: typeof AgentsImport
110
+ parentRoute: typeof rootRoute
111
+ }
112
+ '/chat': {
113
+ id: '/chat'
114
+ path: '/chat'
115
+ fullPath: '/chat'
116
+ preLoaderRoute: typeof ChatImport
117
+ parentRoute: typeof rootRoute
118
+ }
119
+ '/connections': {
120
+ id: '/connections'
121
+ path: '/connections'
122
+ fullPath: '/connections'
123
+ preLoaderRoute: typeof ConnectionsImport
124
+ parentRoute: typeof rootRoute
125
+ }
126
+ '/cron': {
127
+ id: '/cron'
128
+ path: '/cron'
129
+ fullPath: '/cron'
130
+ preLoaderRoute: typeof CronImport
131
+ parentRoute: typeof rootRoute
132
+ }
133
+ '/files': {
134
+ id: '/files'
135
+ path: '/files'
136
+ fullPath: '/files'
137
+ preLoaderRoute: typeof FilesImport
138
+ parentRoute: typeof rootRoute
139
+ }
140
+ '/projects': {
141
+ id: '/projects'
142
+ path: '/projects'
143
+ fullPath: '/projects'
144
+ preLoaderRoute: typeof ProjectsImport
145
+ parentRoute: typeof rootRoute
146
+ }
147
+ '/sessions': {
148
+ id: '/sessions'
149
+ path: '/sessions'
150
+ fullPath: '/sessions'
151
+ preLoaderRoute: typeof SessionsImport
152
+ parentRoute: typeof rootRoute
153
+ }
154
+ '/settings': {
155
+ id: '/settings'
156
+ path: '/settings'
157
+ fullPath: '/settings'
158
+ preLoaderRoute: typeof SettingsImport
159
+ parentRoute: typeof rootRoute
160
+ }
161
+ '/skills': {
162
+ id: '/skills'
163
+ path: '/skills'
164
+ fullPath: '/skills'
165
+ preLoaderRoute: typeof SkillsImport
166
+ parentRoute: typeof rootRoute
167
+ }
168
+ '/usage': {
169
+ id: '/usage'
170
+ path: '/usage'
171
+ fullPath: '/usage'
172
+ preLoaderRoute: typeof UsageImport
173
+ parentRoute: typeof rootRoute
174
+ }
175
+ }
176
+ }
177
+
178
+ // Create and export the route tree
179
+
180
+ export interface FileRoutesByFullPath {
181
+ '/': typeof IndexRoute
182
+ '/agents': typeof AgentsRoute
183
+ '/chat': typeof ChatRoute
184
+ '/connections': typeof ConnectionsRoute
185
+ '/cron': typeof CronRoute
186
+ '/files': typeof FilesRoute
187
+ '/projects': typeof ProjectsRoute
188
+ '/sessions': typeof SessionsRoute
189
+ '/settings': typeof SettingsRoute
190
+ '/skills': typeof SkillsRoute
191
+ '/usage': typeof UsageRoute
192
+ }
193
+
194
+ export interface FileRoutesByTo {
195
+ '/': typeof IndexRoute
196
+ '/agents': typeof AgentsRoute
197
+ '/chat': typeof ChatRoute
198
+ '/connections': typeof ConnectionsRoute
199
+ '/cron': typeof CronRoute
200
+ '/files': typeof FilesRoute
201
+ '/projects': typeof ProjectsRoute
202
+ '/sessions': typeof SessionsRoute
203
+ '/settings': typeof SettingsRoute
204
+ '/skills': typeof SkillsRoute
205
+ '/usage': typeof UsageRoute
206
+ }
207
+
208
+ export interface FileRoutesById {
209
+ __root__: typeof rootRoute
210
+ '/': typeof IndexRoute
211
+ '/agents': typeof AgentsRoute
212
+ '/chat': typeof ChatRoute
213
+ '/connections': typeof ConnectionsRoute
214
+ '/cron': typeof CronRoute
215
+ '/files': typeof FilesRoute
216
+ '/projects': typeof ProjectsRoute
217
+ '/sessions': typeof SessionsRoute
218
+ '/settings': typeof SettingsRoute
219
+ '/skills': typeof SkillsRoute
220
+ '/usage': typeof UsageRoute
221
+ }
222
+
223
+ export interface FileRouteTypes {
224
+ fileRoutesByFullPath: FileRoutesByFullPath
225
+ fullPaths:
226
+ | '/'
227
+ | '/agents'
228
+ | '/chat'
229
+ | '/connections'
230
+ | '/cron'
231
+ | '/files'
232
+ | '/projects'
233
+ | '/sessions'
234
+ | '/settings'
235
+ | '/skills'
236
+ | '/usage'
237
+ fileRoutesByTo: FileRoutesByTo
238
+ to:
239
+ | '/'
240
+ | '/agents'
241
+ | '/chat'
242
+ | '/connections'
243
+ | '/cron'
244
+ | '/files'
245
+ | '/projects'
246
+ | '/sessions'
247
+ | '/settings'
248
+ | '/skills'
249
+ | '/usage'
250
+ id:
251
+ | '__root__'
252
+ | '/'
253
+ | '/agents'
254
+ | '/chat'
255
+ | '/connections'
256
+ | '/cron'
257
+ | '/files'
258
+ | '/projects'
259
+ | '/sessions'
260
+ | '/settings'
261
+ | '/skills'
262
+ | '/usage'
263
+ fileRoutesById: FileRoutesById
264
+ }
265
+
266
+ export interface RootRouteChildren {
267
+ IndexRoute: typeof IndexRoute
268
+ AgentsRoute: typeof AgentsRoute
269
+ ChatRoute: typeof ChatRoute
270
+ ConnectionsRoute: typeof ConnectionsRoute
271
+ CronRoute: typeof CronRoute
272
+ FilesRoute: typeof FilesRoute
273
+ ProjectsRoute: typeof ProjectsRoute
274
+ SessionsRoute: typeof SessionsRoute
275
+ SettingsRoute: typeof SettingsRoute
276
+ SkillsRoute: typeof SkillsRoute
277
+ UsageRoute: typeof UsageRoute
278
+ }
279
+
280
+ const rootRouteChildren: RootRouteChildren = {
281
+ IndexRoute: IndexRoute,
282
+ AgentsRoute: AgentsRoute,
283
+ ChatRoute: ChatRoute,
284
+ ConnectionsRoute: ConnectionsRoute,
285
+ CronRoute: CronRoute,
286
+ FilesRoute: FilesRoute,
287
+ ProjectsRoute: ProjectsRoute,
288
+ SessionsRoute: SessionsRoute,
289
+ SettingsRoute: SettingsRoute,
290
+ SkillsRoute: SkillsRoute,
291
+ UsageRoute: UsageRoute,
292
+ }
293
+
294
+ export const routeTree = rootRoute
295
+ ._addFileChildren(rootRouteChildren)
296
+ ._addFileTypes<FileRouteTypes>()
297
+
298
+ /* ROUTE_MANIFEST_START
299
+ {
300
+ "routes": {
301
+ "__root__": {
302
+ "filePath": "__root.tsx",
303
+ "children": [
304
+ "/",
305
+ "/agents",
306
+ "/chat",
307
+ "/connections",
308
+ "/cron",
309
+ "/files",
310
+ "/projects",
311
+ "/sessions",
312
+ "/settings",
313
+ "/skills",
314
+ "/usage"
315
+ ]
316
+ },
317
+ "/": {
318
+ "filePath": "index.tsx"
319
+ },
320
+ "/agents": {
321
+ "filePath": "agents.tsx"
322
+ },
323
+ "/chat": {
324
+ "filePath": "chat.tsx"
325
+ },
326
+ "/connections": {
327
+ "filePath": "connections.tsx"
328
+ },
329
+ "/cron": {
330
+ "filePath": "cron.tsx"
331
+ },
332
+ "/files": {
333
+ "filePath": "files.tsx"
334
+ },
335
+ "/projects": {
336
+ "filePath": "projects.tsx"
337
+ },
338
+ "/sessions": {
339
+ "filePath": "sessions.tsx"
340
+ },
341
+ "/settings": {
342
+ "filePath": "settings.tsx"
343
+ },
344
+ "/skills": {
345
+ "filePath": "skills.tsx"
346
+ },
347
+ "/usage": {
348
+ "filePath": "usage.tsx"
349
+ }
350
+ }
351
+ }
352
+ ROUTE_MANIFEST_END */
@@ -0,0 +1,10 @@
1
+ import { createRootRoute, Outlet } from "@tanstack/react-router";
2
+ import type { ReactNode } from "react";
3
+
4
+ export const Route = createRootRoute({
5
+ component: RootComponent,
6
+ });
7
+
8
+ function RootComponent() {
9
+ return <Outlet />;
10
+ }
@@ -0,0 +1,255 @@
1
+
2
+ import { createFileRoute } from '@tanstack/react-router';
3
+ import { DashboardLayout } from '../components/DashboardLayout';
4
+ import { useState, useMemo } from 'react';
5
+ import { Bot, Plus, Edit, Trash2, Search, Settings, Zap, X, ChevronDown, Star } from 'lucide-react';
6
+
7
+ // MOCK DATA (to be replaced by Convex)
8
+ const initialAgents = [
9
+ {
10
+ id: 'agent-1',
11
+ name: 'Research Assistant',
12
+ description: 'An agent specialized in gathering and summarizing information from the web.',
13
+ instructions: 'You are a research assistant. Your goal is to find the most relevant and up-to-date information on any given topic. Use search tools and summarize your findings clearly.',
14
+ model: 'gpt-4.1-mini',
15
+ provider: 'OpenAI',
16
+ temperature: 0.7,
17
+ maxTokens: 4096,
18
+ status: 'active',
19
+ },
20
+ {
21
+ id: 'agent-2',
22
+ name: 'Code Generator',
23
+ description: 'Generates code in various programming languages based on user requirements.',
24
+ instructions: 'You are a senior software engineer. Write clean, efficient, and well-documented code. Always ask for clarification if the requirements are ambiguous.',
25
+ model: 'gemini-2.5-flash',
26
+ provider: 'Google',
27
+ temperature: 0.5,
28
+ maxTokens: 8192,
29
+ status: 'inactive',
30
+ },
31
+ {
32
+ id: 'agent-3',
33
+ name: 'Creative Writer',
34
+ description: 'A creative partner for brainstorming and writing stories, scripts, and more.',
35
+ instructions: 'You are a creative writer. Help users brainstorm ideas, develop characters, and write compelling narratives. Be imaginative and inspiring.',
36
+ model: 'grok-4',
37
+ provider: 'xAI',
38
+ temperature: 0.9,
39
+ maxTokens: 2048,
40
+ status: 'active',
41
+ },
42
+ ];
43
+
44
+ // CONVEX PLACEHOLDERS
45
+ // import { useQuery, useMutation } from 'convex/react';
46
+ // import { api } from '../../convex/_generated/api';
47
+
48
+ export const Route = createFileRoute('/agents')({ component: AgentsPage });
49
+
50
+ function AgentsPage() {
51
+ // const agents = useQuery(api.agents.list) || [];
52
+ // const createAgent = useMutation(api.agents.create);
53
+ // const updateAgent = useMutation(api.agents.update);
54
+ // const deleteAgent = useMutation(api.agents.delete);
55
+
56
+ const [agents, setAgents] = useState(initialAgents);
57
+ const [searchQuery, setSearchQuery] = useState('');
58
+ const [isModalOpen, setIsModalOpen] = useState(false);
59
+ const [editingAgent, setEditingAgent] = useState(null);
60
+
61
+ const filteredAgents = useMemo(() =>
62
+ agents.filter(agent =>
63
+ agent.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
64
+ agent.description.toLowerCase().includes(searchQuery.toLowerCase())
65
+ ),
66
+ [agents, searchQuery]
67
+ );
68
+
69
+ const openModal = (agent = null) => {
70
+ setEditingAgent(agent);
71
+ setIsModalOpen(true);
72
+ };
73
+
74
+ const closeModal = () => {
75
+ setEditingAgent(null);
76
+ setIsModalOpen(false);
77
+ };
78
+
79
+ const handleSaveAgent = (agentData) => {
80
+ if (editingAgent) {
81
+ // updateAgent({ id: editingAgent.id, ...agentData });
82
+ setAgents(agents.map(a => a.id === editingAgent.id ? { ...a, ...agentData } : a));
83
+ } else {
84
+ // createAgent(agentData);
85
+ setAgents([...agents, { id: `agent-${Date.now()}`, status: 'active', ...agentData }]);
86
+ }
87
+ closeModal();
88
+ };
89
+
90
+ const handleDeleteAgent = (agentId) => {
91
+ if (window.confirm('Are you sure you want to delete this agent?')) {
92
+ // deleteAgent({ id: agentId });
93
+ setAgents(agents.filter(a => a.id !== agentId));
94
+ }
95
+ };
96
+
97
+ return (
98
+ <DashboardLayout>
99
+ <div className="p-6 bg-background text-foreground">
100
+ <div className="flex justify-between items-center mb-6">
101
+ <h1 className="text-2xl font-bold flex items-center"><Bot className="mr-2" /> Agents</h1>
102
+ <button onClick={() => openModal()} className="bg-primary text-primary-foreground px-4 py-2 rounded-lg flex items-center hover:bg-primary/90">
103
+ <Plus className="mr-2 h-4 w-4" /> Create Agent
104
+ </button>
105
+ </div>
106
+
107
+ <div className="mb-6">
108
+ <div className="relative">
109
+ <Search className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground h-5 w-5" />
110
+ <input
111
+ type="text"
112
+ placeholder="Search agents..."
113
+ value={searchQuery}
114
+ onChange={(e) => setSearchQuery(e.target.value)}
115
+ className="w-full bg-card border border-border rounded-lg pl-10 pr-4 py-2 focus:outline-none focus:ring-2 focus:ring-primary"
116
+ />
117
+ </div>
118
+ </div>
119
+
120
+ {filteredAgents.length > 0 ? (
121
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
122
+ {filteredAgents.map(agent => (
123
+ <AgentCard key={agent.id} agent={agent} onEdit={openModal} onDelete={handleDeleteAgent} />
124
+ ))}
125
+ </div>
126
+ ) : (
127
+ <div className="text-center py-16 border-2 border-dashed border-border rounded-lg">
128
+ <Bot className="mx-auto h-12 w-12 text-muted-foreground" />
129
+ <h3 className="mt-4 text-lg font-medium">No agents found</h3>
130
+ <p className="mt-1 text-sm text-muted-foreground">Create a new agent to get started.</p>
131
+ </div>
132
+ )}
133
+ </div>
134
+ {isModalOpen && <AgentModal agent={editingAgent} onSave={handleSaveAgent} onClose={closeModal} />}
135
+ </DashboardLayout>
136
+ );
137
+ }
138
+
139
+ function AgentCard({ agent, onEdit, onDelete }) {
140
+ return (
141
+ <div className="bg-card border border-border rounded-lg p-4 flex flex-col justify-between hover:shadow-lg transition-shadow">
142
+ <div>
143
+ <div className="flex justify-between items-start">
144
+ <div className="flex items-center mb-2">
145
+ <Bot className="h-8 w-8 text-primary mr-3" />
146
+ <div>
147
+ <h2 className="text-lg font-bold">{agent.name}</h2>
148
+ <span className={`text-xs px-2 py-0.5 rounded-full ${agent.status === 'active' ? 'bg-green-500/20 text-green-400' : 'bg-yellow-500/20 text-yellow-400'}`}>
149
+ {agent.status}
150
+ </span>
151
+ </div>
152
+ </div>
153
+ <div className="flex items-center space-x-2">
154
+ <button onClick={() => onEdit(agent)} className="text-muted-foreground hover:text-foreground"><Edit className="h-4 w-4" /></button>
155
+ <button onClick={() => onDelete(agent.id)} className="text-muted-foreground hover:text-destructive"><Trash2 className="h-4 w-4" /></button>
156
+ </div>
157
+ </div>
158
+ <p className="text-sm text-muted-foreground mb-4 h-10 overflow-hidden">{agent.description}</p>
159
+ <div className="flex items-center text-xs text-muted-foreground space-x-4 mb-4">
160
+ <div className="flex items-center"><Settings className="h-3 w-3 mr-1" /> {agent.model}</div>
161
+ <div className="flex items-center"><Zap className="h-3 w-3 mr-1" /> {agent.provider}</div>
162
+ </div>
163
+ </div>
164
+ <button className="w-full bg-background border border-border text-center py-2 rounded-lg hover:bg-primary/10 text-sm">View Details</button>
165
+ </div>
166
+ );
167
+ }
168
+
169
+ function AgentModal({ agent, onSave, onClose }) {
170
+ const [formData, setFormData] = useState({
171
+ name: agent?.name || '',
172
+ description: agent?.description || '',
173
+ instructions: agent?.instructions || '',
174
+ model: agent?.model || 'gpt-4.1-mini',
175
+ provider: agent?.provider || 'OpenAI',
176
+ temperature: agent?.temperature || 0.7,
177
+ maxTokens: agent?.maxTokens || 4096,
178
+ });
179
+
180
+ const handleChange = (e) => {
181
+ const { name, value } = e.target;
182
+ setFormData(prev => ({ ...prev, [name]: value }));
183
+ };
184
+
185
+ const handleSliderChange = (e) => {
186
+ setFormData(prev => ({ ...prev, temperature: parseFloat(e.target.value) }));
187
+ };
188
+
189
+ const handleSubmit = (e) => {
190
+ e.preventDefault();
191
+ onSave(formData);
192
+ };
193
+
194
+ const providers = ['OpenAI', 'Anthropic', 'OpenRouter', 'Google', 'xAI'];
195
+ const models = {
196
+ OpenAI: ['gpt-4.1-mini', 'gpt-4o', 'gpt-3.5-turbo'],
197
+ Google: ['gemini-2.5-flash', 'gemini-1.5-pro', 'gemini-1.0-pro'],
198
+ Anthropic: ['claude-3-opus', 'claude-3-sonnet', 'claude-3-haiku'],
199
+ OpenRouter: ['openrouter/auto'],
200
+ xAI: ['grok-4', 'grok-4-314b'],
201
+ };
202
+
203
+ return (
204
+ <div className="fixed inset-0 bg-black/60 z-50 flex justify-center items-center">
205
+ <div className="bg-card border border-border rounded-lg shadow-xl w-full max-w-2xl max-h-[90vh] flex flex-col">
206
+ <div className="flex justify-between items-center p-4 border-b border-border">
207
+ <h2 className="text-lg font-bold">{agent ? 'Edit Agent' : 'Create Agent'}</h2>
208
+ <button onClick={onClose} className="text-muted-foreground hover:text-foreground"><X className="h-5 w-5" /></button>
209
+ </div>
210
+ <form onSubmit={handleSubmit} className="flex-grow overflow-y-auto p-6 space-y-4">
211
+ <div>
212
+ <label className="block text-sm font-medium mb-1">Name</label>
213
+ <input type="text" name="name" value={formData.name} onChange={handleChange} className="w-full bg-background border border-border rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary" required />
214
+ </div>
215
+ <div>
216
+ <label className="block text-sm font-medium mb-1">Description</label>
217
+ <input type="text" name="description" value={formData.description} onChange={handleChange} className="w-full bg-background border border-border rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary" required />
218
+ </div>
219
+ <div>
220
+ <label className="block text-sm font-medium mb-1">Instructions</label>
221
+ <textarea name="instructions" value={formData.instructions} onChange={handleChange} rows="6" className="w-full bg-background border border-border rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary" required />
222
+ </div>
223
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
224
+ <div>
225
+ <label className="block text-sm font-medium mb-1">Provider</label>
226
+ <select name="provider" value={formData.provider} onChange={handleChange} className="w-full bg-background border border-border rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary">
227
+ {providers.map(p => <option key={p} value={p}>{p}</option>)}
228
+ </select>
229
+ </div>
230
+ <div>
231
+ <label className="block text-sm font-medium mb-1">Model</label>
232
+ <select name="model" value={formData.model} onChange={handleChange} className="w-full bg-background border border-border rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary">
233
+ {(models[formData.provider] || []).map(m => <option key={m} value={m}>{m}</option>)}
234
+ </select>
235
+ </div>
236
+ </div>
237
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
238
+ <div>
239
+ <label className="block text-sm font-medium mb-1">Temperature: {formData.temperature}</label>
240
+ <input type="range" min="0" max="1" step="0.1" value={formData.temperature} onChange={handleSliderChange} className="w-full h-2 bg-background rounded-lg appearance-none cursor-pointer" />
241
+ </div>
242
+ <div>
243
+ <label className="block text-sm font-medium mb-1">Max Tokens</label>
244
+ <input type="number" name="maxTokens" value={formData.maxTokens} onChange={handleChange} className="w-full bg-background border border-border rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary" />
245
+ </div>
246
+ </div>
247
+ </form>
248
+ <div className="flex justify-end p-4 border-t border-border">
249
+ <button onClick={onClose} className="bg-background border border-border px-4 py-2 rounded-lg mr-2 hover:bg-primary/10">Cancel</button>
250
+ <button onClick={handleSubmit} className="bg-primary text-primary-foreground px-4 py-2 rounded-lg hover:bg-primary/90">Save Agent</button>
251
+ </div>
252
+ </div>
253
+ </div>
254
+ );
255
+ }