@contractspec/example.agent-console 3.7.5 → 3.7.7
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.
- package/.turbo/turbo-build.log +18 -18
- package/AGENTS.md +50 -31
- package/CHANGELOG.md +12 -0
- package/README.md +69 -77
- package/dist/agent/agent.event.js +1 -1
- package/dist/agent/agent.operation.js +1 -1
- package/dist/agent/index.d.ts +5 -5
- package/dist/agent/index.js +1 -1
- package/dist/browser/agent/agent.event.js +1 -1
- package/dist/browser/agent/agent.operation.js +1 -1
- package/dist/browser/agent/index.js +1 -1
- package/dist/browser/index.js +2145 -2145
- package/dist/browser/presentations/index.js +4 -4
- package/dist/browser/run/index.js +536 -536
- package/dist/browser/run/run.event.js +2 -2
- package/dist/browser/run/run.presentation.js +2 -2
- package/dist/browser/tool/index.js +260 -260
- package/dist/browser/tool/tool.event.js +1 -1
- package/dist/browser/tool/tool.presentation.js +2 -2
- package/dist/browser/ui/AgentDashboard.js +956 -956
- package/dist/browser/ui/AgentRunList.js +16 -16
- package/dist/browser/ui/AgentToolRegistry.js +9 -9
- package/dist/browser/ui/hooks/index.js +153 -153
- package/dist/browser/ui/hooks/useAgentList.js +1 -1
- package/dist/browser/ui/hooks/useAgentMutations.js +1 -1
- package/dist/browser/ui/hooks/useRunList.js +1 -1
- package/dist/browser/ui/hooks/useToolList.js +1 -1
- package/dist/browser/ui/index.js +1222 -1222
- package/dist/browser/ui/modals/AgentActionsModal.js +13 -13
- package/dist/browser/ui/modals/CreateAgentModal.js +15 -15
- package/dist/browser/ui/modals/index.js +297 -297
- package/dist/browser/ui/renderers/agent-list.renderer.js +7 -7
- package/dist/browser/ui/renderers/index.js +157 -157
- package/dist/browser/ui/views/AgentListView.js +7 -7
- package/dist/browser/ui/views/RunListView.js +16 -16
- package/dist/browser/ui/views/ToolRegistryView.js +9 -9
- package/dist/browser/ui/views/index.js +97 -97
- package/dist/handlers/index.d.ts +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2145 -2145
- package/dist/node/agent/agent.event.js +1 -1
- package/dist/node/agent/agent.operation.js +1 -1
- package/dist/node/agent/index.js +1 -1
- package/dist/node/index.js +2145 -2145
- package/dist/node/presentations/index.js +4 -4
- package/dist/node/run/index.js +536 -536
- package/dist/node/run/run.event.js +2 -2
- package/dist/node/run/run.presentation.js +2 -2
- package/dist/node/tool/index.js +260 -260
- package/dist/node/tool/tool.event.js +1 -1
- package/dist/node/tool/tool.presentation.js +2 -2
- package/dist/node/ui/AgentDashboard.js +956 -956
- package/dist/node/ui/AgentRunList.js +16 -16
- package/dist/node/ui/AgentToolRegistry.js +9 -9
- package/dist/node/ui/hooks/index.js +153 -153
- package/dist/node/ui/hooks/useAgentList.js +1 -1
- package/dist/node/ui/hooks/useAgentMutations.js +1 -1
- package/dist/node/ui/hooks/useRunList.js +1 -1
- package/dist/node/ui/hooks/useToolList.js +1 -1
- package/dist/node/ui/index.js +1222 -1222
- package/dist/node/ui/modals/AgentActionsModal.js +13 -13
- package/dist/node/ui/modals/CreateAgentModal.js +15 -15
- package/dist/node/ui/modals/index.js +297 -297
- package/dist/node/ui/renderers/agent-list.renderer.js +7 -7
- package/dist/node/ui/renderers/index.js +157 -157
- package/dist/node/ui/views/AgentListView.js +7 -7
- package/dist/node/ui/views/RunListView.js +16 -16
- package/dist/node/ui/views/ToolRegistryView.js +9 -9
- package/dist/node/ui/views/index.js +97 -97
- package/dist/presentations/index.d.ts +3 -5
- package/dist/presentations/index.js +4 -4
- package/dist/run/index.d.ts +7 -7
- package/dist/run/index.js +536 -536
- package/dist/run/run.event.js +2 -2
- package/dist/run/run.handler.d.ts +3 -0
- package/dist/run/run.presentation.js +2 -2
- package/dist/shared/index.d.ts +1 -1
- package/dist/tool/index.d.ts +7 -7
- package/dist/tool/index.js +260 -260
- package/dist/tool/tool.event.js +1 -1
- package/dist/tool/tool.handler.d.ts +1 -1
- package/dist/tool/tool.presentation.js +2 -2
- package/dist/ui/AgentDashboard.js +956 -956
- package/dist/ui/AgentRunList.js +16 -16
- package/dist/ui/AgentToolRegistry.js +9 -9
- package/dist/ui/hooks/index.d.ts +4 -4
- package/dist/ui/hooks/index.js +153 -153
- package/dist/ui/hooks/useAgentList.d.ts +5 -0
- package/dist/ui/hooks/useAgentList.js +1 -1
- package/dist/ui/hooks/useAgentMutations.d.ts +9 -2
- package/dist/ui/hooks/useAgentMutations.js +1 -1
- package/dist/ui/hooks/useRunList.d.ts +5 -0
- package/dist/ui/hooks/useRunList.js +1 -1
- package/dist/ui/hooks/useToolList.d.ts +5 -0
- package/dist/ui/hooks/useToolList.js +1 -1
- package/dist/ui/index.d.ts +3 -3
- package/dist/ui/index.js +1222 -1222
- package/dist/ui/modals/AgentActionsModal.js +13 -13
- package/dist/ui/modals/CreateAgentModal.js +15 -15
- package/dist/ui/modals/index.d.ts +1 -1
- package/dist/ui/modals/index.js +297 -297
- package/dist/ui/renderers/agent-list.markdown.d.ts +5 -0
- package/dist/ui/renderers/agent-list.renderer.js +7 -7
- package/dist/ui/renderers/dashboard.markdown.d.ts +5 -0
- package/dist/ui/renderers/index.d.ts +2 -2
- package/dist/ui/renderers/index.js +157 -157
- package/dist/ui/renderers/run-list.markdown.d.ts +5 -0
- package/dist/ui/renderers/tool-registry.markdown.d.ts +5 -0
- package/dist/ui/views/AgentListView.js +7 -7
- package/dist/ui/views/RunListView.js +16 -16
- package/dist/ui/views/ToolRegistryView.js +9 -9
- package/dist/ui/views/index.js +97 -97
- package/package.json +10 -10
- package/src/agent/agent.entity.ts +111 -111
- package/src/agent/agent.enum.ts +12 -12
- package/src/agent/agent.event.ts +91 -91
- package/src/agent/agent.handler.ts +123 -123
- package/src/agent/agent.operation.ts +400 -400
- package/src/agent/agent.presentation.ts +62 -62
- package/src/agent/agent.schema.ts +175 -175
- package/src/agent/agent.test-spec.ts +48 -48
- package/src/agent/index.ts +46 -51
- package/src/agent.capability.ts +11 -11
- package/src/agent.feature.ts +131 -131
- package/src/docs/agent-console.docblock.ts +42 -42
- package/src/example.ts +35 -35
- package/src/handlers/agent.handlers.ts +522 -521
- package/src/handlers/index.ts +12 -12
- package/src/index.ts +8 -9
- package/src/presentations/index.ts +11 -13
- package/src/run/index.ts +49 -54
- package/src/run/run.entity.ts +137 -137
- package/src/run/run.enum.ts +18 -18
- package/src/run/run.event.ts +174 -174
- package/src/run/run.handler.ts +92 -91
- package/src/run/run.operation.ts +474 -474
- package/src/run/run.presentation.ts +42 -42
- package/src/run/run.schema.ts +126 -126
- package/src/run/run.test-spec.ts +48 -48
- package/src/seeders/index.ts +21 -21
- package/src/shared/index.ts +1 -1
- package/src/shared/mock-agents.ts +76 -76
- package/src/shared/mock-runs.ts +102 -102
- package/src/shared/mock-tools.ts +140 -140
- package/src/shared/overlay-types.ts +23 -23
- package/src/tool/index.ts +39 -44
- package/src/tool/tool.entity.ts +73 -73
- package/src/tool/tool.enum.ts +13 -13
- package/src/tool/tool.event.ts +80 -80
- package/src/tool/tool.handler.ts +102 -102
- package/src/tool/tool.operation.ts +328 -328
- package/src/tool/tool.presentation.ts +43 -43
- package/src/tool/tool.schema.ts +106 -106
- package/src/tool/tool.test-spec.ts +48 -48
- package/src/ui/AgentDashboard.tsx +348 -348
- package/src/ui/hooks/index.ts +7 -7
- package/src/ui/hooks/useAgentList.ts +57 -56
- package/src/ui/hooks/useAgentMutations.ts +160 -159
- package/src/ui/hooks/useRunList.ts +58 -57
- package/src/ui/hooks/useToolList.ts +102 -101
- package/src/ui/index.ts +6 -9
- package/src/ui/modals/AgentActionsModal.tsx +262 -262
- package/src/ui/modals/CreateAgentModal.tsx +232 -232
- package/src/ui/modals/index.ts +1 -1
- package/src/ui/overlays/demo-overlays.ts +52 -52
- package/src/ui/renderers/agent-list.markdown.ts +61 -60
- package/src/ui/renderers/agent-list.renderer.tsx +14 -14
- package/src/ui/renderers/dashboard.markdown.ts +140 -139
- package/src/ui/renderers/index.ts +3 -4
- package/src/ui/renderers/run-list.markdown.ts +48 -47
- package/src/ui/renderers/tool-registry.markdown.ts +66 -65
- package/src/ui/views/AgentListView.tsx +90 -90
- package/src/ui/views/RunListView.tsx +141 -141
- package/src/ui/views/ToolRegistryView.tsx +113 -113
- package/tsconfig.json +7 -8
- package/tsdown.config.js +7 -3
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
StatCard,
|
|
6
|
+
StatCardGroup,
|
|
7
|
+
} from '@contractspec/lib.design-system';
|
|
3
8
|
/**
|
|
4
9
|
* Agent Console Dashboard
|
|
5
10
|
*
|
|
@@ -11,406 +16,401 @@
|
|
|
11
16
|
* - UpdateAgentCommand -> Status changes via modal
|
|
12
17
|
* - ExecuteAgentCommand -> Execute agent via modal
|
|
13
18
|
*/
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} from '
|
|
19
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
20
|
+
import { type Agent, useAgentList } from './hooks/useAgentList';
|
|
21
|
+
import { useAgentMutations } from './hooks/useAgentMutations';
|
|
22
|
+
import { type RunMetrics, useRunList } from './hooks/useRunList';
|
|
23
|
+
import { AgentActionsModal } from './modals/AgentActionsModal';
|
|
24
|
+
import { CreateAgentModal } from './modals/CreateAgentModal';
|
|
20
25
|
// import { AgentListView } from './views/AgentListView';
|
|
21
26
|
import { RunListView } from './views/RunListView';
|
|
22
27
|
import { ToolRegistryView } from './views/ToolRegistryView';
|
|
23
|
-
import { useRunList, type RunMetrics } from './hooks/useRunList';
|
|
24
|
-
import { useAgentList, type Agent } from './hooks/useAgentList';
|
|
25
|
-
import { useAgentMutations } from './hooks/useAgentMutations';
|
|
26
|
-
import { CreateAgentModal } from './modals/CreateAgentModal';
|
|
27
|
-
import { AgentActionsModal } from './modals/AgentActionsModal';
|
|
28
28
|
|
|
29
29
|
type Tab = 'runs' | 'agents' | 'tools' | 'metrics';
|
|
30
30
|
|
|
31
31
|
export function AgentDashboard() {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
const [activeTab, setActiveTab] = useState<Tab>('runs');
|
|
33
|
+
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
|
34
|
+
const [selectedAgent, setSelectedAgent] = useState<Agent | null>(null);
|
|
35
|
+
const [isAgentActionsOpen, setIsAgentActionsOpen] = useState(false);
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
const { metrics, refetch: refetchRuns } = useRunList();
|
|
38
|
+
const { refetch: refetchAgents } = useAgentList();
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
const mutations = useAgentMutations({
|
|
41
|
+
onSuccess: () => {
|
|
42
|
+
refetchAgents();
|
|
43
|
+
refetchRuns();
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
const handleAgentClick = useCallback((agent: Agent) => {
|
|
48
|
+
setSelectedAgent(agent);
|
|
49
|
+
setIsAgentActionsOpen(true);
|
|
50
|
+
}, []);
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
const tabs: { id: Tab; label: string; icon: string }[] = [
|
|
53
|
+
{ id: 'runs', label: 'Runs', icon: '▶' },
|
|
54
|
+
{ id: 'agents', label: 'Agents', icon: '🤖' },
|
|
55
|
+
{ id: 'tools', label: 'Tools', icon: '🔧' },
|
|
56
|
+
{ id: 'metrics', label: 'Metrics', icon: '📊' },
|
|
57
|
+
];
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
59
|
+
// Compute summary stats from metrics
|
|
60
|
+
const summaryStats = useMemo(() => {
|
|
61
|
+
if (!metrics) {
|
|
62
|
+
return [
|
|
63
|
+
{ label: 'Total Runs', value: '-', hint: 'Loading...' },
|
|
64
|
+
{ label: 'Success Rate', value: '-', hint: '' },
|
|
65
|
+
{ label: 'Total Tokens', value: '-', hint: '' },
|
|
66
|
+
{ label: 'Total Cost', value: '-', hint: '' },
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
return [
|
|
70
|
+
{
|
|
71
|
+
label: 'Total Runs',
|
|
72
|
+
value: metrics.totalRuns.toLocaleString(),
|
|
73
|
+
hint: `${(metrics.successRate * 100).toFixed(0)}% success`,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
label: 'Success Rate',
|
|
77
|
+
value: `${(metrics.successRate * 100).toFixed(0)}%`,
|
|
78
|
+
hint: 'of all runs',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
label: 'Total Tokens',
|
|
82
|
+
value:
|
|
83
|
+
metrics.totalTokens >= 1000000
|
|
84
|
+
? `${(metrics.totalTokens / 1000000).toFixed(1)}M`
|
|
85
|
+
: `${(metrics.totalTokens / 1000).toFixed(0)}K`,
|
|
86
|
+
hint: 'This period',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
label: 'Total Cost',
|
|
90
|
+
value: `$${metrics.totalCostUsd.toFixed(2)}`,
|
|
91
|
+
hint: 'This period',
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
}, [metrics]);
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
96
|
+
return (
|
|
97
|
+
<div className="space-y-6">
|
|
98
|
+
{/* Header */}
|
|
99
|
+
<div className="flex items-center justify-between">
|
|
100
|
+
<h2 className="font-bold text-2xl">AI Agent Console</h2>
|
|
101
|
+
<Button onPress={() => setIsCreateModalOpen(true)}>
|
|
102
|
+
<span className="mr-2">+</span> New Agent
|
|
103
|
+
</Button>
|
|
104
|
+
</div>
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
106
|
+
{/* Summary Stats Row */}
|
|
107
|
+
<StatCardGroup>
|
|
108
|
+
{summaryStats.map((stat, i) => (
|
|
109
|
+
<StatCard
|
|
110
|
+
key={i}
|
|
111
|
+
label={stat.label}
|
|
112
|
+
value={stat.value}
|
|
113
|
+
hint={stat.hint}
|
|
114
|
+
/>
|
|
115
|
+
))}
|
|
116
|
+
</StatCardGroup>
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
118
|
+
{/* Navigation Tabs */}
|
|
119
|
+
<nav className="flex gap-1 rounded-lg bg-muted p-1" role="tablist">
|
|
120
|
+
{tabs.map((tab) => (
|
|
121
|
+
<button
|
|
122
|
+
key={tab.id}
|
|
123
|
+
type="button"
|
|
124
|
+
role="tab"
|
|
125
|
+
aria-selected={activeTab === tab.id}
|
|
126
|
+
onClick={() => setActiveTab(tab.id)}
|
|
127
|
+
className={`flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 font-medium text-sm transition-colors ${
|
|
128
|
+
activeTab === tab.id
|
|
129
|
+
? 'bg-background text-foreground shadow-sm'
|
|
130
|
+
: 'text-muted-foreground hover:text-foreground'
|
|
131
|
+
}`}
|
|
132
|
+
>
|
|
133
|
+
<span>{tab.icon}</span>
|
|
134
|
+
{tab.label}
|
|
135
|
+
</button>
|
|
136
|
+
))}
|
|
137
|
+
</nav>
|
|
138
138
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
139
|
+
{/* Tab Content */}
|
|
140
|
+
<div className="min-h-[400px]" role="tabpanel">
|
|
141
|
+
{activeTab === 'runs' && <RunListView />}
|
|
142
|
+
{activeTab === 'agents' && (
|
|
143
|
+
<AgentListViewWithActions onAgentClick={handleAgentClick} />
|
|
144
|
+
)}
|
|
145
|
+
{activeTab === 'tools' && <ToolRegistryView />}
|
|
146
|
+
{activeTab === 'metrics' && <MetricsView metrics={metrics} />}
|
|
147
|
+
</div>
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
149
|
+
{/* Create Agent Modal */}
|
|
150
|
+
<CreateAgentModal
|
|
151
|
+
isOpen={isCreateModalOpen}
|
|
152
|
+
onClose={() => setIsCreateModalOpen(false)}
|
|
153
|
+
onSubmit={async (input) => {
|
|
154
|
+
await mutations.createAgent(input);
|
|
155
|
+
}}
|
|
156
|
+
isLoading={mutations.createState.loading}
|
|
157
|
+
/>
|
|
158
158
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
159
|
+
{/* Agent Actions Modal */}
|
|
160
|
+
<AgentActionsModal
|
|
161
|
+
isOpen={isAgentActionsOpen}
|
|
162
|
+
agent={selectedAgent}
|
|
163
|
+
onClose={() => {
|
|
164
|
+
setIsAgentActionsOpen(false);
|
|
165
|
+
setSelectedAgent(null);
|
|
166
|
+
}}
|
|
167
|
+
onActivate={async (agentId) => {
|
|
168
|
+
await mutations.activateAgent(agentId);
|
|
169
|
+
}}
|
|
170
|
+
onPause={async (agentId) => {
|
|
171
|
+
await mutations.pauseAgent(agentId);
|
|
172
|
+
}}
|
|
173
|
+
onArchive={async (agentId) => {
|
|
174
|
+
await mutations.archiveAgent(agentId);
|
|
175
|
+
}}
|
|
176
|
+
onExecute={async (agentId, message) => {
|
|
177
|
+
await mutations.executeAgent({ agentId, message });
|
|
178
|
+
}}
|
|
179
|
+
isLoading={mutations.isLoading}
|
|
180
|
+
/>
|
|
181
|
+
</div>
|
|
182
|
+
);
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
/**
|
|
186
186
|
* Agent List View with click handler
|
|
187
187
|
*/
|
|
188
188
|
function AgentListViewWithActions({
|
|
189
|
-
|
|
189
|
+
onAgentClick,
|
|
190
190
|
}: {
|
|
191
|
-
|
|
191
|
+
onAgentClick: (agent: Agent) => void;
|
|
192
192
|
}) {
|
|
193
|
-
|
|
193
|
+
const { data, loading, error, stats, refetch } = useAgentList();
|
|
194
194
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
195
|
+
if (loading && !data) {
|
|
196
|
+
return (
|
|
197
|
+
<div className="flex h-64 items-center justify-center text-muted-foreground">
|
|
198
|
+
Loading agents...
|
|
199
|
+
</div>
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
202
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
203
|
+
if (error) {
|
|
204
|
+
return (
|
|
205
|
+
<div className="flex h-64 flex-col items-center justify-center text-destructive">
|
|
206
|
+
<p>Failed to load agents: {error.message}</p>
|
|
207
|
+
<Button variant="outline" onPress={refetch} className="mt-2">
|
|
208
|
+
Retry
|
|
209
|
+
</Button>
|
|
210
|
+
</div>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
213
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
214
|
+
if (!data?.items.length) {
|
|
215
|
+
return (
|
|
216
|
+
<div className="flex h-64 flex-col items-center justify-center text-muted-foreground">
|
|
217
|
+
<p className="font-medium text-lg">No agents yet</p>
|
|
218
|
+
<p className="text-sm">Create your first AI agent to get started.</p>
|
|
219
|
+
</div>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
222
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
223
|
+
return (
|
|
224
|
+
<div className="space-y-4">
|
|
225
|
+
{/* Stats */}
|
|
226
|
+
{stats && (
|
|
227
|
+
<div className="flex gap-4 text-sm">
|
|
228
|
+
<span>Total: {stats.total}</span>
|
|
229
|
+
<span className="text-green-600">Active: {stats.active}</span>
|
|
230
|
+
<span className="text-yellow-600">Paused: {stats.paused}</span>
|
|
231
|
+
<span className="text-blue-600">Draft: {stats.draft}</span>
|
|
232
|
+
</div>
|
|
233
|
+
)}
|
|
234
234
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
235
|
+
{/* Agent Grid */}
|
|
236
|
+
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
237
|
+
{data.items.map((agent) => (
|
|
238
|
+
<AgentCard
|
|
239
|
+
key={agent.id}
|
|
240
|
+
agent={agent}
|
|
241
|
+
onClick={() => onAgentClick(agent)}
|
|
242
|
+
/>
|
|
243
|
+
))}
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
246
|
+
);
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
/**
|
|
250
250
|
* Agent Card Component
|
|
251
251
|
*/
|
|
252
252
|
function AgentCard({ agent, onClick }: { agent: Agent; onClick: () => void }) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
253
|
+
const statusColors: Record<string, string> = {
|
|
254
|
+
ACTIVE:
|
|
255
|
+
'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400',
|
|
256
|
+
DRAFT: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400',
|
|
257
|
+
PAUSED:
|
|
258
|
+
'bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400',
|
|
259
|
+
ARCHIVED: 'bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-400',
|
|
260
|
+
};
|
|
261
261
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
262
|
+
return (
|
|
263
|
+
<div
|
|
264
|
+
onClick={onClick}
|
|
265
|
+
className="cursor-pointer rounded-xl border border-border bg-card p-4 transition-all hover:shadow-md"
|
|
266
|
+
role="button"
|
|
267
|
+
tabIndex={0}
|
|
268
|
+
onKeyDown={(e) => {
|
|
269
|
+
if (e.key === 'Enter' || e.key === ' ') onClick();
|
|
270
|
+
}}
|
|
271
|
+
>
|
|
272
|
+
<div className="flex items-start justify-between">
|
|
273
|
+
<div className="min-w-0 flex-1">
|
|
274
|
+
<h3 className="truncate font-semibold">{agent.name}</h3>
|
|
275
|
+
<p className="text-muted-foreground text-sm">
|
|
276
|
+
{agent.modelProvider} / {agent.modelName}
|
|
277
|
+
</p>
|
|
278
|
+
</div>
|
|
279
|
+
<span
|
|
280
|
+
className={`rounded-full px-2 py-0.5 font-medium text-xs ${statusColors[agent.status]}`}
|
|
281
|
+
>
|
|
282
|
+
{agent.status}
|
|
283
|
+
</span>
|
|
284
|
+
</div>
|
|
285
|
+
{agent.description && (
|
|
286
|
+
<p className="mt-2 line-clamp-2 text-muted-foreground text-sm">
|
|
287
|
+
{agent.description}
|
|
288
|
+
</p>
|
|
289
|
+
)}
|
|
290
|
+
<div className="mt-3 flex items-center justify-between">
|
|
291
|
+
<span className="text-muted-foreground text-xs">{agent.modelName}</span>
|
|
292
|
+
<Button variant="ghost" size="sm" onPress={onClick}>
|
|
293
|
+
Actions
|
|
294
|
+
</Button>
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
);
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
/**
|
|
301
301
|
* Metrics View - Shows usage analytics
|
|
302
302
|
*/
|
|
303
303
|
function MetricsView({ metrics }: { metrics: RunMetrics | null }) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
304
|
+
if (!metrics) {
|
|
305
|
+
return (
|
|
306
|
+
<div className="flex h-64 items-center justify-center text-muted-foreground">
|
|
307
|
+
Loading metrics...
|
|
308
|
+
</div>
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
311
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
312
|
+
// Calculate derived metrics
|
|
313
|
+
const completedRuns = Math.round(metrics.totalRuns * metrics.successRate);
|
|
314
|
+
const failedRuns = metrics.totalRuns - completedRuns;
|
|
315
315
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
316
|
+
return (
|
|
317
|
+
<div className="space-y-6">
|
|
318
|
+
<h3 className="font-semibold text-lg">Usage Analytics</h3>
|
|
319
319
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
320
|
+
<div className="grid gap-6 md:grid-cols-2">
|
|
321
|
+
{/* Success/Failure breakdown */}
|
|
322
|
+
<div className="rounded-xl border border-border bg-card p-4">
|
|
323
|
+
<h4 className="font-medium">Run Outcomes</h4>
|
|
324
|
+
<div className="mt-4 space-y-3">
|
|
325
|
+
<ProgressBar
|
|
326
|
+
label="Completed"
|
|
327
|
+
value={completedRuns}
|
|
328
|
+
total={metrics.totalRuns}
|
|
329
|
+
color="bg-green-500"
|
|
330
|
+
/>
|
|
331
|
+
<ProgressBar
|
|
332
|
+
label="Failed"
|
|
333
|
+
value={failedRuns}
|
|
334
|
+
total={metrics.totalRuns}
|
|
335
|
+
color="bg-red-500"
|
|
336
|
+
/>
|
|
337
|
+
</div>
|
|
338
|
+
</div>
|
|
339
339
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
340
|
+
{/* Key Stats */}
|
|
341
|
+
<div className="rounded-xl border border-border bg-card p-4">
|
|
342
|
+
<h4 className="font-medium">Performance</h4>
|
|
343
|
+
<dl className="mt-4 grid grid-cols-2 gap-4">
|
|
344
|
+
<div>
|
|
345
|
+
<dt className="text-muted-foreground text-sm">Avg Duration</dt>
|
|
346
|
+
<dd className="font-semibold text-xl">
|
|
347
|
+
{(metrics.averageDurationMs / 1000).toFixed(1)}s
|
|
348
|
+
</dd>
|
|
349
|
+
</div>
|
|
350
|
+
<div>
|
|
351
|
+
<dt className="text-muted-foreground text-sm">Success Rate</dt>
|
|
352
|
+
<dd className="font-semibold text-xl">
|
|
353
|
+
{(metrics.successRate * 100).toFixed(0)}%
|
|
354
|
+
</dd>
|
|
355
|
+
</div>
|
|
356
|
+
</dl>
|
|
357
|
+
</div>
|
|
358
|
+
</div>
|
|
359
359
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
360
|
+
{/* Key Metrics */}
|
|
361
|
+
<div className="rounded-xl border border-border bg-card p-4">
|
|
362
|
+
<h4 className="font-medium">Key Metrics</h4>
|
|
363
|
+
<dl className="mt-4 grid gap-4 sm:grid-cols-3">
|
|
364
|
+
<div>
|
|
365
|
+
<dt className="text-muted-foreground text-sm">Total Runs</dt>
|
|
366
|
+
<dd className="font-semibold text-2xl">
|
|
367
|
+
{metrics.totalRuns.toLocaleString()}
|
|
368
|
+
</dd>
|
|
369
|
+
</div>
|
|
370
|
+
<div>
|
|
371
|
+
<dt className="text-muted-foreground text-sm">Total Tokens</dt>
|
|
372
|
+
<dd className="font-semibold text-2xl">
|
|
373
|
+
{(metrics.totalTokens / 1000).toFixed(0)}K
|
|
374
|
+
</dd>
|
|
375
|
+
</div>
|
|
376
|
+
<div>
|
|
377
|
+
<dt className="text-muted-foreground text-sm">Cost per Run</dt>
|
|
378
|
+
<dd className="font-semibold text-2xl">
|
|
379
|
+
$
|
|
380
|
+
{metrics.totalRuns > 0
|
|
381
|
+
? (metrics.totalCostUsd / metrics.totalRuns).toFixed(4)
|
|
382
|
+
: '0'}
|
|
383
|
+
</dd>
|
|
384
|
+
</div>
|
|
385
|
+
</dl>
|
|
386
|
+
</div>
|
|
387
|
+
</div>
|
|
388
|
+
);
|
|
389
389
|
}
|
|
390
390
|
|
|
391
391
|
function ProgressBar({
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
392
|
+
label,
|
|
393
|
+
value,
|
|
394
|
+
total,
|
|
395
|
+
color,
|
|
396
396
|
}: {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
397
|
+
label: string;
|
|
398
|
+
value: number;
|
|
399
|
+
total: number;
|
|
400
|
+
color: string;
|
|
401
401
|
}) {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
402
|
+
const pct = total > 0 ? (value / total) * 100 : 0;
|
|
403
|
+
return (
|
|
404
|
+
<div>
|
|
405
|
+
<div className="flex justify-between text-sm">
|
|
406
|
+
<span>{label}</span>
|
|
407
|
+
<span className="text-muted-foreground">
|
|
408
|
+
{value} ({pct.toFixed(0)}%)
|
|
409
|
+
</span>
|
|
410
|
+
</div>
|
|
411
|
+
<div className="mt-1 h-2 overflow-hidden rounded-full bg-muted">
|
|
412
|
+
<div className={`h-full ${color}`} style={{ width: `${pct}%` }} />
|
|
413
|
+
</div>
|
|
414
|
+
</div>
|
|
415
|
+
);
|
|
416
416
|
}
|