@contractspec/example.agent-console 1.46.0 → 1.47.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 (204) hide show
  1. package/.turbo/turbo-build$colon$bundle.log +275 -128
  2. package/.turbo/turbo-build.log +274 -127
  3. package/CHANGELOG.md +46 -0
  4. package/dist/agent/agent.entity.d.ts +36 -36
  5. package/dist/agent/agent.entity.d.ts.map +1 -1
  6. package/dist/agent/agent.enum.d.ts +4 -4
  7. package/dist/agent/agent.enum.d.ts.map +1 -1
  8. package/dist/agent/agent.event.d.ts +31 -31
  9. package/dist/agent/agent.event.d.ts.map +1 -1
  10. package/dist/agent/agent.event.js +5 -5
  11. package/dist/agent/agent.event.js.map +1 -1
  12. package/dist/agent/agent.handler.js.map +1 -1
  13. package/dist/agent/agent.operation.d.ts +117 -117
  14. package/dist/agent/agent.operation.d.ts.map +1 -1
  15. package/dist/agent/agent.presentation.d.ts +4 -5
  16. package/dist/agent/agent.presentation.d.ts.map +1 -1
  17. package/dist/agent/agent.presentation.js +7 -7
  18. package/dist/agent/agent.presentation.js.map +1 -1
  19. package/dist/agent/agent.schema.d.ts +95 -95
  20. package/dist/agent/agent.schema.d.ts.map +1 -1
  21. package/dist/agent/agent.test-spec.d.ts +8 -0
  22. package/dist/agent/agent.test-spec.d.ts.map +1 -0
  23. package/dist/agent/agent.test-spec.js +65 -0
  24. package/dist/agent/agent.test-spec.js.map +1 -0
  25. package/dist/agent.capability.d.ts +7 -0
  26. package/dist/agent.capability.d.ts.map +1 -0
  27. package/dist/agent.capability.js +20 -0
  28. package/dist/agent.capability.js.map +1 -0
  29. package/dist/agent.feature.d.ts.map +1 -1
  30. package/dist/agent.feature.js +4 -2
  31. package/dist/agent.feature.js.map +1 -1
  32. package/dist/example.d.ts +2 -2
  33. package/dist/example.d.ts.map +1 -1
  34. package/dist/example.js +4 -2
  35. package/dist/example.js.map +1 -1
  36. package/dist/handlers/agent.handlers.d.ts +135 -0
  37. package/dist/handlers/agent.handlers.d.ts.map +1 -0
  38. package/dist/handlers/agent.handlers.js +263 -0
  39. package/dist/handlers/agent.handlers.js.map +1 -0
  40. package/dist/handlers/index.d.ts +2 -1
  41. package/dist/handlers/index.js +2 -1
  42. package/dist/index.d.ts +19 -1
  43. package/dist/index.js +19 -1
  44. package/dist/run/run.entity.d.ts +56 -56
  45. package/dist/run/run.enum.d.ts +5 -5
  46. package/dist/run/run.event.d.ts +71 -71
  47. package/dist/run/run.event.d.ts.map +1 -1
  48. package/dist/run/run.event.js +8 -8
  49. package/dist/run/run.event.js.map +1 -1
  50. package/dist/run/run.operation.d.ts +175 -175
  51. package/dist/run/run.operation.d.ts.map +1 -1
  52. package/dist/run/run.presentation.d.ts +3 -4
  53. package/dist/run/run.presentation.d.ts.map +1 -1
  54. package/dist/run/run.presentation.js +5 -5
  55. package/dist/run/run.presentation.js.map +1 -1
  56. package/dist/run/run.schema.d.ts +99 -99
  57. package/dist/run/run.test-spec.d.ts +8 -0
  58. package/dist/run/run.test-spec.d.ts.map +1 -0
  59. package/dist/run/run.test-spec.js +65 -0
  60. package/dist/run/run.test-spec.js.map +1 -0
  61. package/dist/seeders/index.d.ts +10 -0
  62. package/dist/seeders/index.d.ts.map +1 -0
  63. package/dist/seeders/index.js +20 -0
  64. package/dist/seeders/index.js.map +1 -0
  65. package/dist/shared/overlay-types.d.ts +34 -0
  66. package/dist/shared/overlay-types.d.ts.map +1 -0
  67. package/dist/shared/overlay-types.js +0 -0
  68. package/dist/tool/tool.entity.d.ts +24 -24
  69. package/dist/tool/tool.enum.d.ts +4 -4
  70. package/dist/tool/tool.event.d.ts +25 -25
  71. package/dist/tool/tool.event.js +4 -4
  72. package/dist/tool/tool.event.js.map +1 -1
  73. package/dist/tool/tool.handler.d.ts.map +1 -1
  74. package/dist/tool/tool.operation.d.ts +101 -101
  75. package/dist/tool/tool.presentation.d.ts +3 -4
  76. package/dist/tool/tool.presentation.d.ts.map +1 -1
  77. package/dist/tool/tool.presentation.js +5 -5
  78. package/dist/tool/tool.presentation.js.map +1 -1
  79. package/dist/tool/tool.schema.d.ts +52 -52
  80. package/dist/tool/tool.schema.d.ts.map +1 -1
  81. package/dist/tool/tool.test-spec.d.ts +8 -0
  82. package/dist/tool/tool.test-spec.d.ts.map +1 -0
  83. package/dist/tool/tool.test-spec.js +65 -0
  84. package/dist/tool/tool.test-spec.js.map +1 -0
  85. package/dist/ui/AgentDashboard.d.ts +7 -0
  86. package/dist/ui/AgentDashboard.d.ts.map +1 -0
  87. package/dist/ui/AgentDashboard.js +420 -0
  88. package/dist/ui/AgentDashboard.js.map +1 -0
  89. package/dist/ui/AgentRunList.d.ts +2 -0
  90. package/dist/ui/AgentRunList.js +5 -0
  91. package/dist/ui/AgentToolRegistry.d.ts +2 -0
  92. package/dist/ui/AgentToolRegistry.js +5 -0
  93. package/dist/ui/hooks/index.d.ts +6 -0
  94. package/dist/ui/hooks/index.js +8 -0
  95. package/dist/ui/hooks/useAgentList.d.ts +28 -0
  96. package/dist/ui/hooks/useAgentList.d.ts.map +1 -0
  97. package/dist/ui/hooks/useAgentList.js +66 -0
  98. package/dist/ui/hooks/useAgentList.js.map +1 -0
  99. package/dist/ui/hooks/useAgentMutations.d.ts +29 -0
  100. package/dist/ui/hooks/useAgentMutations.d.ts.map +1 -0
  101. package/dist/ui/hooks/useAgentMutations.js +124 -0
  102. package/dist/ui/hooks/useAgentMutations.js.map +1 -0
  103. package/dist/ui/hooks/useRunList.d.ts +24 -0
  104. package/dist/ui/hooks/useRunList.d.ts.map +1 -0
  105. package/dist/ui/hooks/useRunList.js +66 -0
  106. package/dist/ui/hooks/useRunList.js.map +1 -0
  107. package/dist/ui/hooks/useToolList.d.ts +40 -0
  108. package/dist/ui/hooks/useToolList.d.ts.map +1 -0
  109. package/dist/ui/hooks/useToolList.js +96 -0
  110. package/dist/ui/hooks/useToolList.js.map +1 -0
  111. package/dist/ui/index.d.ts +24 -0
  112. package/dist/ui/index.js +24 -0
  113. package/dist/ui/modals/AgentActionsModal.d.ts +27 -0
  114. package/dist/ui/modals/AgentActionsModal.d.ts.map +1 -0
  115. package/dist/ui/modals/AgentActionsModal.js +262 -0
  116. package/dist/ui/modals/AgentActionsModal.js.map +1 -0
  117. package/dist/ui/modals/CreateAgentModal.d.ts +25 -0
  118. package/dist/ui/modals/CreateAgentModal.d.ts.map +1 -0
  119. package/dist/ui/modals/CreateAgentModal.js +214 -0
  120. package/dist/ui/modals/CreateAgentModal.js.map +1 -0
  121. package/dist/ui/modals/index.d.ts +3 -0
  122. package/dist/ui/modals/index.js +4 -0
  123. package/dist/ui/overlays/demo-overlays.d.ts +19 -0
  124. package/dist/ui/overlays/demo-overlays.d.ts.map +1 -0
  125. package/dist/ui/overlays/demo-overlays.js +73 -0
  126. package/dist/ui/overlays/demo-overlays.js.map +1 -0
  127. package/dist/ui/overlays/index.d.ts +2 -0
  128. package/dist/ui/overlays/index.js +3 -0
  129. package/dist/ui/renderers/agent-list.markdown.d.ts +15 -0
  130. package/dist/ui/renderers/agent-list.markdown.d.ts.map +1 -0
  131. package/dist/ui/renderers/agent-list.markdown.js +51 -0
  132. package/dist/ui/renderers/agent-list.markdown.js.map +1 -0
  133. package/dist/ui/renderers/agent-list.renderer.d.ts +11 -0
  134. package/dist/ui/renderers/agent-list.renderer.d.ts.map +1 -0
  135. package/dist/ui/renderers/agent-list.renderer.js +19 -0
  136. package/dist/ui/renderers/agent-list.renderer.js.map +1 -0
  137. package/dist/ui/renderers/dashboard.markdown.d.ts +15 -0
  138. package/dist/ui/renderers/dashboard.markdown.d.ts.map +1 -0
  139. package/dist/ui/renderers/dashboard.markdown.js +100 -0
  140. package/dist/ui/renderers/dashboard.markdown.js.map +1 -0
  141. package/dist/ui/renderers/index.d.ts +6 -0
  142. package/dist/ui/renderers/index.js +7 -0
  143. package/dist/ui/renderers/run-list.markdown.d.ts +15 -0
  144. package/dist/ui/renderers/run-list.markdown.d.ts.map +1 -0
  145. package/dist/ui/renderers/run-list.markdown.js +44 -0
  146. package/dist/ui/renderers/run-list.markdown.js.map +1 -0
  147. package/dist/ui/renderers/tool-registry.markdown.d.ts +15 -0
  148. package/dist/ui/renderers/tool-registry.markdown.d.ts.map +1 -0
  149. package/dist/ui/renderers/tool-registry.markdown.js +55 -0
  150. package/dist/ui/renderers/tool-registry.markdown.js.map +1 -0
  151. package/dist/ui/views/AgentListView.d.ts +7 -0
  152. package/dist/ui/views/AgentListView.d.ts.map +1 -0
  153. package/dist/ui/views/AgentListView.js +93 -0
  154. package/dist/ui/views/AgentListView.js.map +1 -0
  155. package/dist/ui/views/RunListView.d.ts +14 -0
  156. package/dist/ui/views/RunListView.d.ts.map +1 -0
  157. package/dist/ui/views/RunListView.js +165 -0
  158. package/dist/ui/views/RunListView.js.map +1 -0
  159. package/dist/ui/views/ToolRegistryView.d.ts +14 -0
  160. package/dist/ui/views/ToolRegistryView.d.ts.map +1 -0
  161. package/dist/ui/views/ToolRegistryView.js +97 -0
  162. package/dist/ui/views/ToolRegistryView.js.map +1 -0
  163. package/dist/ui/views/index.d.ts +4 -0
  164. package/dist/ui/views/index.js +5 -0
  165. package/package.json +46 -10
  166. package/src/agent/agent.presentation.ts +7 -8
  167. package/src/agent/agent.test-spec.ts +55 -0
  168. package/src/agent.capability.ts +13 -0
  169. package/src/agent.feature.ts +3 -2
  170. package/src/example.ts +3 -3
  171. package/src/handlers/agent.handlers.ts +572 -0
  172. package/src/handlers/index.ts +3 -0
  173. package/src/index.ts +5 -0
  174. package/src/run/run.presentation.ts +5 -6
  175. package/src/run/run.test-spec.ts +55 -0
  176. package/src/seeders/index.ts +29 -0
  177. package/src/shared/overlay-types.ts +39 -0
  178. package/src/tool/tool.presentation.ts +5 -6
  179. package/src/tool/tool.test-spec.ts +55 -0
  180. package/src/ui/AgentDashboard.tsx +416 -0
  181. package/src/ui/AgentRunList.tsx +8 -0
  182. package/src/ui/AgentToolRegistry.tsx +8 -0
  183. package/src/ui/hooks/index.ts +14 -0
  184. package/src/ui/hooks/useAgentList.ts +80 -0
  185. package/src/ui/hooks/useAgentMutations.ts +156 -0
  186. package/src/ui/hooks/useRunList.ts +81 -0
  187. package/src/ui/hooks/useToolList.ts +122 -0
  188. package/src/ui/index.ts +21 -0
  189. package/src/ui/modals/AgentActionsModal.tsx +306 -0
  190. package/src/ui/modals/CreateAgentModal.tsx +257 -0
  191. package/src/ui/modals/index.ts +2 -0
  192. package/src/ui/overlays/demo-overlays.ts +77 -0
  193. package/src/ui/overlays/index.ts +1 -0
  194. package/src/ui/renderers/agent-list.markdown.ts +84 -0
  195. package/src/ui/renderers/agent-list.renderer.tsx +27 -0
  196. package/src/ui/renderers/dashboard.markdown.ts +169 -0
  197. package/src/ui/renderers/index.ts +12 -0
  198. package/src/ui/renderers/run-list.markdown.ts +75 -0
  199. package/src/ui/renderers/tool-registry.markdown.ts +91 -0
  200. package/src/ui/views/AgentListView.tsx +113 -0
  201. package/src/ui/views/RunListView.tsx +173 -0
  202. package/src/ui/views/ToolRegistryView.tsx +140 -0
  203. package/src/ui/views/index.ts +6 -0
  204. 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
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * View components for agent-console template
3
+ */
4
+ export { AgentListView } from './AgentListView';
5
+ export { RunListView } from './RunListView';
6
+ export { ToolRegistryView } from './ToolRegistryView';