@contractspec/example.agent-console 1.46.1 → 1.48.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.
- package/.turbo/turbo-build$colon$bundle.log +275 -128
- package/.turbo/turbo-build.log +274 -127
- package/CHANGELOG.md +52 -0
- package/dist/agent/agent.entity.d.ts +36 -36
- package/dist/agent/agent.entity.d.ts.map +1 -1
- package/dist/agent/agent.enum.d.ts +4 -4
- package/dist/agent/agent.enum.d.ts.map +1 -1
- package/dist/agent/agent.event.d.ts +31 -31
- package/dist/agent/agent.event.d.ts.map +1 -1
- package/dist/agent/agent.event.js +5 -5
- package/dist/agent/agent.event.js.map +1 -1
- package/dist/agent/agent.handler.js.map +1 -1
- package/dist/agent/agent.operation.d.ts +117 -117
- package/dist/agent/agent.operation.d.ts.map +1 -1
- package/dist/agent/agent.presentation.d.ts +4 -5
- package/dist/agent/agent.presentation.d.ts.map +1 -1
- package/dist/agent/agent.presentation.js +7 -7
- package/dist/agent/agent.presentation.js.map +1 -1
- package/dist/agent/agent.schema.d.ts +95 -95
- package/dist/agent/agent.schema.d.ts.map +1 -1
- package/dist/agent/agent.test-spec.d.ts +8 -0
- package/dist/agent/agent.test-spec.d.ts.map +1 -0
- package/dist/agent/agent.test-spec.js +65 -0
- package/dist/agent/agent.test-spec.js.map +1 -0
- package/dist/agent.capability.d.ts +7 -0
- package/dist/agent.capability.d.ts.map +1 -0
- package/dist/agent.capability.js +20 -0
- package/dist/agent.capability.js.map +1 -0
- package/dist/agent.feature.d.ts.map +1 -1
- package/dist/agent.feature.js +4 -2
- package/dist/agent.feature.js.map +1 -1
- package/dist/example.d.ts +2 -2
- package/dist/example.d.ts.map +1 -1
- package/dist/example.js +4 -2
- package/dist/example.js.map +1 -1
- package/dist/handlers/agent.handlers.d.ts +135 -0
- package/dist/handlers/agent.handlers.d.ts.map +1 -0
- package/dist/handlers/agent.handlers.js +263 -0
- package/dist/handlers/agent.handlers.js.map +1 -0
- package/dist/handlers/index.d.ts +2 -1
- package/dist/handlers/index.js +2 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +19 -1
- package/dist/run/run.entity.d.ts +56 -56
- package/dist/run/run.enum.d.ts +5 -5
- package/dist/run/run.event.d.ts +71 -71
- package/dist/run/run.event.js +8 -8
- package/dist/run/run.event.js.map +1 -1
- package/dist/run/run.operation.d.ts +175 -175
- package/dist/run/run.presentation.d.ts +3 -4
- package/dist/run/run.presentation.d.ts.map +1 -1
- package/dist/run/run.presentation.js +5 -5
- package/dist/run/run.presentation.js.map +1 -1
- package/dist/run/run.schema.d.ts +99 -99
- package/dist/run/run.test-spec.d.ts +8 -0
- package/dist/run/run.test-spec.d.ts.map +1 -0
- package/dist/run/run.test-spec.js +65 -0
- package/dist/run/run.test-spec.js.map +1 -0
- package/dist/seeders/index.d.ts +10 -0
- package/dist/seeders/index.d.ts.map +1 -0
- package/dist/seeders/index.js +20 -0
- package/dist/seeders/index.js.map +1 -0
- package/dist/shared/overlay-types.d.ts +34 -0
- package/dist/shared/overlay-types.d.ts.map +1 -0
- package/dist/shared/overlay-types.js +0 -0
- package/dist/tool/tool.entity.d.ts +24 -24
- package/dist/tool/tool.enum.d.ts +4 -4
- package/dist/tool/tool.event.d.ts +25 -25
- package/dist/tool/tool.event.js +4 -4
- package/dist/tool/tool.event.js.map +1 -1
- package/dist/tool/tool.handler.d.ts.map +1 -1
- package/dist/tool/tool.operation.d.ts +101 -101
- package/dist/tool/tool.presentation.d.ts +3 -4
- package/dist/tool/tool.presentation.d.ts.map +1 -1
- package/dist/tool/tool.presentation.js +5 -5
- package/dist/tool/tool.presentation.js.map +1 -1
- package/dist/tool/tool.schema.d.ts +52 -52
- package/dist/tool/tool.schema.d.ts.map +1 -1
- package/dist/tool/tool.test-spec.d.ts +8 -0
- package/dist/tool/tool.test-spec.d.ts.map +1 -0
- package/dist/tool/tool.test-spec.js +65 -0
- package/dist/tool/tool.test-spec.js.map +1 -0
- package/dist/ui/AgentDashboard.d.ts +7 -0
- package/dist/ui/AgentDashboard.d.ts.map +1 -0
- package/dist/ui/AgentDashboard.js +420 -0
- package/dist/ui/AgentDashboard.js.map +1 -0
- package/dist/ui/AgentRunList.d.ts +2 -0
- package/dist/ui/AgentRunList.js +5 -0
- package/dist/ui/AgentToolRegistry.d.ts +2 -0
- package/dist/ui/AgentToolRegistry.js +5 -0
- package/dist/ui/hooks/index.d.ts +6 -0
- package/dist/ui/hooks/index.js +8 -0
- package/dist/ui/hooks/useAgentList.d.ts +28 -0
- package/dist/ui/hooks/useAgentList.d.ts.map +1 -0
- package/dist/ui/hooks/useAgentList.js +66 -0
- package/dist/ui/hooks/useAgentList.js.map +1 -0
- package/dist/ui/hooks/useAgentMutations.d.ts +29 -0
- package/dist/ui/hooks/useAgentMutations.d.ts.map +1 -0
- package/dist/ui/hooks/useAgentMutations.js +124 -0
- package/dist/ui/hooks/useAgentMutations.js.map +1 -0
- package/dist/ui/hooks/useRunList.d.ts +24 -0
- package/dist/ui/hooks/useRunList.d.ts.map +1 -0
- package/dist/ui/hooks/useRunList.js +66 -0
- package/dist/ui/hooks/useRunList.js.map +1 -0
- package/dist/ui/hooks/useToolList.d.ts +40 -0
- package/dist/ui/hooks/useToolList.d.ts.map +1 -0
- package/dist/ui/hooks/useToolList.js +96 -0
- package/dist/ui/hooks/useToolList.js.map +1 -0
- package/dist/ui/index.d.ts +24 -0
- package/dist/ui/index.js +24 -0
- package/dist/ui/modals/AgentActionsModal.d.ts +27 -0
- package/dist/ui/modals/AgentActionsModal.d.ts.map +1 -0
- package/dist/ui/modals/AgentActionsModal.js +262 -0
- package/dist/ui/modals/AgentActionsModal.js.map +1 -0
- package/dist/ui/modals/CreateAgentModal.d.ts +25 -0
- package/dist/ui/modals/CreateAgentModal.d.ts.map +1 -0
- package/dist/ui/modals/CreateAgentModal.js +214 -0
- package/dist/ui/modals/CreateAgentModal.js.map +1 -0
- package/dist/ui/modals/index.d.ts +3 -0
- package/dist/ui/modals/index.js +4 -0
- package/dist/ui/overlays/demo-overlays.d.ts +19 -0
- package/dist/ui/overlays/demo-overlays.d.ts.map +1 -0
- package/dist/ui/overlays/demo-overlays.js +73 -0
- package/dist/ui/overlays/demo-overlays.js.map +1 -0
- package/dist/ui/overlays/index.d.ts +2 -0
- package/dist/ui/overlays/index.js +3 -0
- package/dist/ui/renderers/agent-list.markdown.d.ts +15 -0
- package/dist/ui/renderers/agent-list.markdown.d.ts.map +1 -0
- package/dist/ui/renderers/agent-list.markdown.js +51 -0
- package/dist/ui/renderers/agent-list.markdown.js.map +1 -0
- package/dist/ui/renderers/agent-list.renderer.d.ts +11 -0
- package/dist/ui/renderers/agent-list.renderer.d.ts.map +1 -0
- package/dist/ui/renderers/agent-list.renderer.js +19 -0
- package/dist/ui/renderers/agent-list.renderer.js.map +1 -0
- package/dist/ui/renderers/dashboard.markdown.d.ts +15 -0
- package/dist/ui/renderers/dashboard.markdown.d.ts.map +1 -0
- package/dist/ui/renderers/dashboard.markdown.js +100 -0
- package/dist/ui/renderers/dashboard.markdown.js.map +1 -0
- package/dist/ui/renderers/index.d.ts +6 -0
- package/dist/ui/renderers/index.js +7 -0
- package/dist/ui/renderers/run-list.markdown.d.ts +15 -0
- package/dist/ui/renderers/run-list.markdown.d.ts.map +1 -0
- package/dist/ui/renderers/run-list.markdown.js +44 -0
- package/dist/ui/renderers/run-list.markdown.js.map +1 -0
- package/dist/ui/renderers/tool-registry.markdown.d.ts +15 -0
- package/dist/ui/renderers/tool-registry.markdown.d.ts.map +1 -0
- package/dist/ui/renderers/tool-registry.markdown.js +55 -0
- package/dist/ui/renderers/tool-registry.markdown.js.map +1 -0
- package/dist/ui/views/AgentListView.d.ts +7 -0
- package/dist/ui/views/AgentListView.d.ts.map +1 -0
- package/dist/ui/views/AgentListView.js +93 -0
- package/dist/ui/views/AgentListView.js.map +1 -0
- package/dist/ui/views/RunListView.d.ts +14 -0
- package/dist/ui/views/RunListView.d.ts.map +1 -0
- package/dist/ui/views/RunListView.js +165 -0
- package/dist/ui/views/RunListView.js.map +1 -0
- package/dist/ui/views/ToolRegistryView.d.ts +14 -0
- package/dist/ui/views/ToolRegistryView.d.ts.map +1 -0
- package/dist/ui/views/ToolRegistryView.js +97 -0
- package/dist/ui/views/ToolRegistryView.js.map +1 -0
- package/dist/ui/views/index.d.ts +4 -0
- package/dist/ui/views/index.js +5 -0
- package/package.json +46 -10
- package/src/agent/agent.presentation.ts +7 -8
- package/src/agent/agent.test-spec.ts +55 -0
- package/src/agent.capability.ts +13 -0
- package/src/agent.feature.ts +3 -2
- package/src/example.ts +3 -3
- package/src/handlers/agent.handlers.ts +572 -0
- package/src/handlers/index.ts +3 -0
- package/src/index.ts +5 -0
- package/src/run/run.presentation.ts +5 -6
- package/src/run/run.test-spec.ts +55 -0
- package/src/seeders/index.ts +29 -0
- package/src/shared/overlay-types.ts +39 -0
- package/src/tool/tool.presentation.ts +5 -6
- package/src/tool/tool.test-spec.ts +55 -0
- package/src/ui/AgentDashboard.tsx +416 -0
- package/src/ui/AgentRunList.tsx +8 -0
- package/src/ui/AgentToolRegistry.tsx +8 -0
- package/src/ui/hooks/index.ts +14 -0
- package/src/ui/hooks/useAgentList.ts +80 -0
- package/src/ui/hooks/useAgentMutations.ts +156 -0
- package/src/ui/hooks/useRunList.ts +81 -0
- package/src/ui/hooks/useToolList.ts +122 -0
- package/src/ui/index.ts +21 -0
- package/src/ui/modals/AgentActionsModal.tsx +306 -0
- package/src/ui/modals/CreateAgentModal.tsx +257 -0
- package/src/ui/modals/index.ts +2 -0
- package/src/ui/overlays/demo-overlays.ts +77 -0
- package/src/ui/overlays/index.ts +1 -0
- package/src/ui/renderers/agent-list.markdown.ts +84 -0
- package/src/ui/renderers/agent-list.renderer.tsx +27 -0
- package/src/ui/renderers/dashboard.markdown.ts +169 -0
- package/src/ui/renderers/index.ts +12 -0
- package/src/ui/renderers/run-list.markdown.ts +75 -0
- package/src/ui/renderers/tool-registry.markdown.ts +91 -0
- package/src/ui/views/AgentListView.tsx +113 -0
- package/src/ui/views/RunListView.tsx +173 -0
- package/src/ui/views/ToolRegistryView.tsx +140 -0
- package/src/ui/views/index.ts +6 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown Renderer for Run List Presentation
|
|
3
|
+
*
|
|
4
|
+
* Uses dynamic import for handlers to ensure correct build order.
|
|
5
|
+
*/
|
|
6
|
+
import type {
|
|
7
|
+
PresentationRenderer,
|
|
8
|
+
PresentationSpec,
|
|
9
|
+
} from '@contractspec/lib.contracts';
|
|
10
|
+
import type { Run } from '../hooks/useRunList';
|
|
11
|
+
import { mockListRunsHandler } from '@contractspec/example.agent-console/handlers';
|
|
12
|
+
|
|
13
|
+
interface RunListOutput {
|
|
14
|
+
items: Run[];
|
|
15
|
+
total: number;
|
|
16
|
+
hasMore: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function formatDuration(ms: number): string {
|
|
20
|
+
if (ms < 1000) return `${ms}ms`;
|
|
21
|
+
if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
|
|
22
|
+
return `${(ms / 60000).toFixed(1)}m`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Markdown renderer for agent-console.run.list presentation
|
|
27
|
+
* Only handles RunListView component
|
|
28
|
+
*/
|
|
29
|
+
export const runListMarkdownRenderer: PresentationRenderer<{
|
|
30
|
+
mimeType: string;
|
|
31
|
+
body: string;
|
|
32
|
+
}> = {
|
|
33
|
+
target: 'markdown',
|
|
34
|
+
render: async (desc: PresentationSpec) => {
|
|
35
|
+
// Only handle RunListView
|
|
36
|
+
if (
|
|
37
|
+
desc.source.type !== 'component' ||
|
|
38
|
+
desc.source.componentKey !== 'RunListView'
|
|
39
|
+
) {
|
|
40
|
+
throw new Error('runListMarkdownRenderer: not RunListView');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Fetch data using mock handler
|
|
44
|
+
const data = (await mockListRunsHandler({
|
|
45
|
+
organizationId: 'demo-org',
|
|
46
|
+
limit: 20,
|
|
47
|
+
offset: 0,
|
|
48
|
+
})) as RunListOutput;
|
|
49
|
+
|
|
50
|
+
// Generate markdown
|
|
51
|
+
const lines: string[] = [
|
|
52
|
+
`# ${desc.meta.description ?? 'Agent Runs'}`,
|
|
53
|
+
'',
|
|
54
|
+
`> ${desc.meta.key} v${desc.meta.version}`,
|
|
55
|
+
'',
|
|
56
|
+
`**Total Runs:** ${data.total}`,
|
|
57
|
+
'',
|
|
58
|
+
'## Recent Runs',
|
|
59
|
+
'',
|
|
60
|
+
'| ID | Agent | Status | Duration | Tokens | Cost |',
|
|
61
|
+
'| --- | --- | --- | --- | --- | --- |',
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
for (const run of data.items.slice(0, 10)) {
|
|
65
|
+
lines.push(
|
|
66
|
+
`| ${run.id.slice(-8)} | ${run.agentName} | ${run.status} | ${run.durationMs ? formatDuration(run.durationMs) : '-'} | ${run.totalTokens} | $${run.estimatedCostUsd?.toFixed(4) ?? '-'} |`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
mimeType: 'text/markdown',
|
|
72
|
+
body: lines.join('\n'),
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown Renderer for Tool Registry Presentation
|
|
3
|
+
*
|
|
4
|
+
* Uses dynamic import for handlers to ensure correct build order.
|
|
5
|
+
*/
|
|
6
|
+
import type {
|
|
7
|
+
PresentationRenderer,
|
|
8
|
+
PresentationSpec,
|
|
9
|
+
} from '@contractspec/lib.contracts';
|
|
10
|
+
import { mockListToolsHandler } from '@contractspec/example.agent-console/handlers';
|
|
11
|
+
|
|
12
|
+
interface ToolItem {
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
version: string;
|
|
17
|
+
category: string;
|
|
18
|
+
status: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Markdown renderer for agent-console.tool.registry presentation
|
|
23
|
+
* Only handles ToolRegistryView component
|
|
24
|
+
*/
|
|
25
|
+
export const toolRegistryMarkdownRenderer: PresentationRenderer<{
|
|
26
|
+
mimeType: string;
|
|
27
|
+
body: string;
|
|
28
|
+
}> = {
|
|
29
|
+
target: 'markdown',
|
|
30
|
+
render: async (desc: PresentationSpec) => {
|
|
31
|
+
// Only handle ToolRegistryView
|
|
32
|
+
if (
|
|
33
|
+
desc.source.type !== 'component' ||
|
|
34
|
+
desc.source.componentKey !== 'ToolRegistryView'
|
|
35
|
+
) {
|
|
36
|
+
throw new Error('toolRegistryMarkdownRenderer: not ToolRegistryView');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Fetch data using mock handler
|
|
40
|
+
const data = await mockListToolsHandler({
|
|
41
|
+
organizationId: 'demo-org',
|
|
42
|
+
limit: 50,
|
|
43
|
+
offset: 0,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Generate markdown
|
|
47
|
+
const lines: string[] = [
|
|
48
|
+
`# ${desc.meta.description ?? 'Tool Registry'}`,
|
|
49
|
+
'',
|
|
50
|
+
`> ${desc.meta.key} v${desc.meta.version}`,
|
|
51
|
+
'',
|
|
52
|
+
`**Total Tools:** ${data.total}`,
|
|
53
|
+
'',
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
// Group by category
|
|
57
|
+
const byCategory: Record<string, ToolItem[]> = {};
|
|
58
|
+
for (const tool of data.items as ToolItem[]) {
|
|
59
|
+
const cat = tool.category;
|
|
60
|
+
if (!byCategory[cat]) byCategory[cat] = [];
|
|
61
|
+
byCategory[cat].push(tool);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
for (const [category, tools] of Object.entries(byCategory).sort()) {
|
|
65
|
+
lines.push(`## ${category} (${tools.length})`);
|
|
66
|
+
lines.push('');
|
|
67
|
+
|
|
68
|
+
for (const tool of tools) {
|
|
69
|
+
const statusIcon =
|
|
70
|
+
tool.status === 'ACTIVE'
|
|
71
|
+
? '✅'
|
|
72
|
+
: tool.status === 'DEPRECATED'
|
|
73
|
+
? '⚠️'
|
|
74
|
+
: '❌';
|
|
75
|
+
lines.push(`### ${statusIcon} ${tool.name} v${tool.version}`);
|
|
76
|
+
lines.push('');
|
|
77
|
+
lines.push(`> \`${tool.id}\``);
|
|
78
|
+
lines.push('');
|
|
79
|
+
if (tool.description) {
|
|
80
|
+
lines.push(tool.description);
|
|
81
|
+
lines.push('');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
mimeType: 'text/markdown',
|
|
88
|
+
body: lines.join('\n'),
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Agent List View
|
|
5
|
+
*
|
|
6
|
+
* Displays a list of AI agents with their status and basic info.
|
|
7
|
+
* Uses design-system components with correct props.
|
|
8
|
+
*/
|
|
9
|
+
import {
|
|
10
|
+
Button,
|
|
11
|
+
StatCard,
|
|
12
|
+
StatCardGroup,
|
|
13
|
+
EntityCard,
|
|
14
|
+
StatusChip,
|
|
15
|
+
LoaderBlock,
|
|
16
|
+
ErrorState,
|
|
17
|
+
EmptyState,
|
|
18
|
+
} from '@contractspec/lib.design-system';
|
|
19
|
+
import { useAgentList, type Agent } from '../hooks/useAgentList';
|
|
20
|
+
|
|
21
|
+
function getStatusTone(
|
|
22
|
+
status: Agent['status']
|
|
23
|
+
): 'success' | 'warning' | 'neutral' {
|
|
24
|
+
switch (status) {
|
|
25
|
+
case 'ACTIVE':
|
|
26
|
+
return 'success';
|
|
27
|
+
case 'PAUSED':
|
|
28
|
+
case 'DRAFT':
|
|
29
|
+
return 'warning';
|
|
30
|
+
case 'ARCHIVED':
|
|
31
|
+
return 'neutral';
|
|
32
|
+
default:
|
|
33
|
+
return 'neutral';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function AgentListView() {
|
|
38
|
+
const { data, loading, error, stats, refetch } = useAgentList();
|
|
39
|
+
|
|
40
|
+
if (loading && !data) {
|
|
41
|
+
return <LoaderBlock label="Loading agents..." />;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (error) {
|
|
45
|
+
return (
|
|
46
|
+
<ErrorState
|
|
47
|
+
title="Failed to load agents"
|
|
48
|
+
description={error.message}
|
|
49
|
+
onRetry={refetch}
|
|
50
|
+
retryLabel="Retry"
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!data?.items.length) {
|
|
56
|
+
return (
|
|
57
|
+
<EmptyState
|
|
58
|
+
title="No agents yet"
|
|
59
|
+
description="Create your first AI agent to get started."
|
|
60
|
+
/>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div className="space-y-6">
|
|
66
|
+
{/* Stats */}
|
|
67
|
+
{stats && (
|
|
68
|
+
<StatCardGroup>
|
|
69
|
+
<StatCard label="Total Agents" value={stats.total} />
|
|
70
|
+
<StatCard label="Active" value={stats.active} />
|
|
71
|
+
<StatCard label="Paused" value={stats.paused} />
|
|
72
|
+
<StatCard label="Draft" value={stats.draft} />
|
|
73
|
+
</StatCardGroup>
|
|
74
|
+
)}
|
|
75
|
+
|
|
76
|
+
{/* Actions */}
|
|
77
|
+
<div className="flex items-center justify-between">
|
|
78
|
+
<h3 className="text-lg font-semibold">Agents</h3>
|
|
79
|
+
<Button onPress={() => alert('Create Agent clicked!')}>
|
|
80
|
+
Create Agent
|
|
81
|
+
</Button>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
{/* Agent List */}
|
|
85
|
+
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
86
|
+
{data.items.map((agent) => (
|
|
87
|
+
<EntityCard
|
|
88
|
+
key={agent.id}
|
|
89
|
+
cardTitle={agent.name}
|
|
90
|
+
cardSubtitle={agent.modelName}
|
|
91
|
+
meta={
|
|
92
|
+
<p className="text-muted-foreground text-sm">
|
|
93
|
+
{agent.description}
|
|
94
|
+
</p>
|
|
95
|
+
}
|
|
96
|
+
chips={
|
|
97
|
+
<StatusChip
|
|
98
|
+
tone={getStatusTone(agent.status)}
|
|
99
|
+
label={agent.status}
|
|
100
|
+
/>
|
|
101
|
+
}
|
|
102
|
+
footer={
|
|
103
|
+
<span className="text-muted-foreground text-xs">
|
|
104
|
+
Created {agent.createdAt.toLocaleDateString()}
|
|
105
|
+
</span>
|
|
106
|
+
}
|
|
107
|
+
onClick={() => alert(`View agent: ${agent.name}`)}
|
|
108
|
+
/>
|
|
109
|
+
))}
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Run List View - Shows agent execution runs with stats
|
|
5
|
+
*/
|
|
6
|
+
import {
|
|
7
|
+
StatCard,
|
|
8
|
+
StatCardGroup,
|
|
9
|
+
StatusChip,
|
|
10
|
+
EmptyState,
|
|
11
|
+
LoaderBlock,
|
|
12
|
+
ErrorState,
|
|
13
|
+
} from '@contractspec/lib.design-system';
|
|
14
|
+
import { useRunList, type Run } from '../hooks/useRunList';
|
|
15
|
+
|
|
16
|
+
interface RunListViewProps {
|
|
17
|
+
agentId?: string;
|
|
18
|
+
onRunClick?: (runId: string) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getStatusTone(
|
|
22
|
+
status: Run['status']
|
|
23
|
+
): 'success' | 'warning' | 'neutral' | 'danger' {
|
|
24
|
+
switch (status) {
|
|
25
|
+
case 'COMPLETED':
|
|
26
|
+
return 'success';
|
|
27
|
+
case 'RUNNING':
|
|
28
|
+
return 'warning';
|
|
29
|
+
case 'QUEUED':
|
|
30
|
+
return 'neutral';
|
|
31
|
+
case 'FAILED':
|
|
32
|
+
case 'CANCELLED':
|
|
33
|
+
return 'danger';
|
|
34
|
+
default:
|
|
35
|
+
return 'neutral';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function formatDuration(ms?: number): string {
|
|
40
|
+
if (!ms) return '-';
|
|
41
|
+
if (ms < 1000) return `${ms}ms`;
|
|
42
|
+
if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
|
|
43
|
+
return `${(ms / 60000).toFixed(1)}m`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function formatTokens(tokens: number): string {
|
|
47
|
+
if (tokens < 1000) return tokens.toString();
|
|
48
|
+
if (tokens < 1000000) return `${(tokens / 1000).toFixed(1)}K`;
|
|
49
|
+
return `${(tokens / 1000000).toFixed(2)}M`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function formatCost(cost?: number): string {
|
|
53
|
+
if (!cost) return '-';
|
|
54
|
+
return `$${cost.toFixed(4)}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function RunListView({ agentId, onRunClick }: RunListViewProps) {
|
|
58
|
+
const { data, metrics, loading, error, refetch } = useRunList({ agentId });
|
|
59
|
+
|
|
60
|
+
if (loading && !data) {
|
|
61
|
+
return <LoaderBlock label="Loading runs..." />;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (error) {
|
|
65
|
+
return (
|
|
66
|
+
<ErrorState
|
|
67
|
+
title="Failed to load runs"
|
|
68
|
+
description={error.message}
|
|
69
|
+
onRetry={refetch}
|
|
70
|
+
retryLabel="Retry"
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!data?.items.length) {
|
|
76
|
+
return (
|
|
77
|
+
<EmptyState
|
|
78
|
+
title="No runs yet"
|
|
79
|
+
description="Execute an agent to see run history here."
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<div className="space-y-6">
|
|
86
|
+
{/* Metrics Stats */}
|
|
87
|
+
{metrics && (
|
|
88
|
+
<StatCardGroup>
|
|
89
|
+
<StatCard label="Total Runs" value={metrics.totalRuns} />
|
|
90
|
+
<StatCard
|
|
91
|
+
label="Success Rate"
|
|
92
|
+
value={`${(metrics.successRate * 100).toFixed(1)}%`}
|
|
93
|
+
/>
|
|
94
|
+
<StatCard
|
|
95
|
+
label="Total Tokens"
|
|
96
|
+
value={formatTokens(metrics.totalTokens)}
|
|
97
|
+
/>
|
|
98
|
+
<StatCard
|
|
99
|
+
label="Total Cost"
|
|
100
|
+
value={`$${metrics.totalCostUsd.toFixed(2)}`}
|
|
101
|
+
/>
|
|
102
|
+
</StatCardGroup>
|
|
103
|
+
)}
|
|
104
|
+
|
|
105
|
+
{/* Run List */}
|
|
106
|
+
<div className="border-border rounded-lg border">
|
|
107
|
+
<table className="w-full">
|
|
108
|
+
<thead className="border-border bg-muted/30 border-b">
|
|
109
|
+
<tr>
|
|
110
|
+
<th className="text-muted-foreground px-4 py-3 text-left text-sm font-medium">
|
|
111
|
+
Run
|
|
112
|
+
</th>
|
|
113
|
+
<th className="text-muted-foreground px-4 py-3 text-left text-sm font-medium">
|
|
114
|
+
Agent
|
|
115
|
+
</th>
|
|
116
|
+
<th className="text-muted-foreground px-4 py-3 text-left text-sm font-medium">
|
|
117
|
+
Status
|
|
118
|
+
</th>
|
|
119
|
+
<th className="text-muted-foreground px-4 py-3 text-right text-sm font-medium">
|
|
120
|
+
Tokens
|
|
121
|
+
</th>
|
|
122
|
+
<th className="text-muted-foreground px-4 py-3 text-right text-sm font-medium">
|
|
123
|
+
Duration
|
|
124
|
+
</th>
|
|
125
|
+
<th className="text-muted-foreground px-4 py-3 text-right text-sm font-medium">
|
|
126
|
+
Cost
|
|
127
|
+
</th>
|
|
128
|
+
</tr>
|
|
129
|
+
</thead>
|
|
130
|
+
<tbody className="divide-border divide-y">
|
|
131
|
+
{data.items.map((run: Run) => (
|
|
132
|
+
<tr
|
|
133
|
+
key={run.id}
|
|
134
|
+
className="hover:bg-muted/50 cursor-pointer transition-colors"
|
|
135
|
+
onClick={() => onRunClick?.(run.id)}
|
|
136
|
+
>
|
|
137
|
+
<td className="px-4 py-3">
|
|
138
|
+
<div className="font-mono text-sm">{run.id.slice(-8)}</div>
|
|
139
|
+
<div className="text-muted-foreground text-xs">
|
|
140
|
+
{run.queuedAt.toLocaleString()}
|
|
141
|
+
</div>
|
|
142
|
+
</td>
|
|
143
|
+
<td className="px-4 py-3">
|
|
144
|
+
<span className="font-medium">{run.agentName}</span>
|
|
145
|
+
</td>
|
|
146
|
+
<td className="px-4 py-3">
|
|
147
|
+
<StatusChip
|
|
148
|
+
tone={getStatusTone(run.status)}
|
|
149
|
+
label={run.status}
|
|
150
|
+
/>
|
|
151
|
+
</td>
|
|
152
|
+
<td className="px-4 py-3 text-right font-mono text-sm">
|
|
153
|
+
{formatTokens(run.totalTokens)}
|
|
154
|
+
</td>
|
|
155
|
+
<td className="px-4 py-3 text-right font-mono text-sm">
|
|
156
|
+
{formatDuration(run.durationMs)}
|
|
157
|
+
</td>
|
|
158
|
+
<td className="px-4 py-3 text-right font-mono text-sm">
|
|
159
|
+
{formatCost(run.estimatedCostUsd)}
|
|
160
|
+
</td>
|
|
161
|
+
</tr>
|
|
162
|
+
))}
|
|
163
|
+
</tbody>
|
|
164
|
+
</table>
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
{/* Pagination */}
|
|
168
|
+
<div className="text-muted-foreground text-center text-sm">
|
|
169
|
+
Showing {data.items.length} of {data.total} runs
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
);
|
|
173
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tool Registry View - Shows available tools organized by category
|
|
5
|
+
*/
|
|
6
|
+
import {
|
|
7
|
+
StatCard,
|
|
8
|
+
StatCardGroup,
|
|
9
|
+
StatusChip,
|
|
10
|
+
EntityCard,
|
|
11
|
+
EmptyState,
|
|
12
|
+
LoaderBlock,
|
|
13
|
+
ErrorState,
|
|
14
|
+
Button,
|
|
15
|
+
} from '@contractspec/lib.design-system';
|
|
16
|
+
import { useToolList, type Tool } from '../hooks/useToolList';
|
|
17
|
+
|
|
18
|
+
interface ToolRegistryViewProps {
|
|
19
|
+
onToolClick?: (toolId: string) => void;
|
|
20
|
+
onCreateTool?: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const categoryIcons: Record<string, string> = {
|
|
24
|
+
RETRIEVAL: '🔍',
|
|
25
|
+
COMPUTATION: '🧮',
|
|
26
|
+
COMMUNICATION: '📧',
|
|
27
|
+
INTEGRATION: '🔗',
|
|
28
|
+
UTILITY: '🛠️',
|
|
29
|
+
CUSTOM: '⚙️',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function getStatusTone(
|
|
33
|
+
status: Tool['status']
|
|
34
|
+
): 'success' | 'warning' | 'neutral' | 'danger' {
|
|
35
|
+
switch (status) {
|
|
36
|
+
case 'ACTIVE':
|
|
37
|
+
return 'success';
|
|
38
|
+
case 'DRAFT':
|
|
39
|
+
return 'neutral';
|
|
40
|
+
case 'DEPRECATED':
|
|
41
|
+
return 'warning';
|
|
42
|
+
case 'DISABLED':
|
|
43
|
+
return 'danger';
|
|
44
|
+
default:
|
|
45
|
+
return 'neutral';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function ToolRegistryView({
|
|
50
|
+
onToolClick,
|
|
51
|
+
onCreateTool,
|
|
52
|
+
}: ToolRegistryViewProps) {
|
|
53
|
+
const { data, loading, error, groupedByCategory, categoryStats, refetch } =
|
|
54
|
+
useToolList();
|
|
55
|
+
|
|
56
|
+
if (loading && !data) {
|
|
57
|
+
return <LoaderBlock label="Loading tools..." />;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (error) {
|
|
61
|
+
return (
|
|
62
|
+
<ErrorState
|
|
63
|
+
title="Failed to load tools"
|
|
64
|
+
description={error.message}
|
|
65
|
+
onRetry={refetch}
|
|
66
|
+
retryLabel="Retry"
|
|
67
|
+
/>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!data?.items.length) {
|
|
72
|
+
return (
|
|
73
|
+
<EmptyState
|
|
74
|
+
title="No tools registered"
|
|
75
|
+
description="Create your first tool to extend agent capabilities."
|
|
76
|
+
primaryAction={
|
|
77
|
+
onCreateTool ? (
|
|
78
|
+
<Button onPress={onCreateTool}>Create Tool</Button>
|
|
79
|
+
) : undefined
|
|
80
|
+
}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<div className="space-y-8">
|
|
87
|
+
{/* Category Stats */}
|
|
88
|
+
<StatCardGroup>
|
|
89
|
+
<StatCard label="Total Tools" value={data.total} />
|
|
90
|
+
{categoryStats.slice(0, 3).map(({ category, count }) => (
|
|
91
|
+
<StatCard
|
|
92
|
+
key={category}
|
|
93
|
+
label={`${categoryIcons[category] ?? ''} ${category}`}
|
|
94
|
+
value={count}
|
|
95
|
+
/>
|
|
96
|
+
))}
|
|
97
|
+
</StatCardGroup>
|
|
98
|
+
|
|
99
|
+
{/* Tools by Category */}
|
|
100
|
+
{Object.entries(groupedByCategory).map(([category, tools]) => (
|
|
101
|
+
<section key={category} className="space-y-4">
|
|
102
|
+
<div className="flex items-center gap-2">
|
|
103
|
+
<span className="text-2xl">{categoryIcons[category]}</span>
|
|
104
|
+
<h3 className="text-lg font-semibold">{category}</h3>
|
|
105
|
+
<span className="bg-muted text-muted-foreground rounded-full px-2 py-0.5 text-xs">
|
|
106
|
+
{(tools as Tool[]).length}
|
|
107
|
+
</span>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
111
|
+
{(tools as Tool[]).map((tool) => (
|
|
112
|
+
<EntityCard
|
|
113
|
+
key={tool.id}
|
|
114
|
+
cardTitle={tool.name}
|
|
115
|
+
cardSubtitle={`v${tool.version}`}
|
|
116
|
+
meta={
|
|
117
|
+
<p className="text-muted-foreground text-sm">
|
|
118
|
+
{tool.description}
|
|
119
|
+
</p>
|
|
120
|
+
}
|
|
121
|
+
chips={
|
|
122
|
+
<StatusChip
|
|
123
|
+
tone={getStatusTone(tool.status)}
|
|
124
|
+
label={tool.status}
|
|
125
|
+
/>
|
|
126
|
+
}
|
|
127
|
+
footer={
|
|
128
|
+
<code className="text-muted-foreground text-xs">
|
|
129
|
+
{tool.name}
|
|
130
|
+
</code>
|
|
131
|
+
}
|
|
132
|
+
onClick={onToolClick ? () => onToolClick(tool.id) : undefined}
|
|
133
|
+
/>
|
|
134
|
+
))}
|
|
135
|
+
</div>
|
|
136
|
+
</section>
|
|
137
|
+
))}
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
}
|