@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.
- package/.turbo/turbo-build$colon$bundle.log +275 -128
- package/.turbo/turbo-build.log +274 -127
- package/CHANGELOG.md +46 -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.d.ts.map +1 -1
- 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.operation.d.ts.map +1 -1
- 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,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for Agent Console mutations (commands)
|
|
3
|
+
*
|
|
4
|
+
* Uses runtime-local database-backed handlers for:
|
|
5
|
+
* - CreateAgentCommand
|
|
6
|
+
* - UpdateAgentCommand
|
|
7
|
+
*/
|
|
8
|
+
import { useCallback, useState } from 'react';
|
|
9
|
+
import { useTemplateRuntime } from '@contractspec/lib.example-shared-ui';
|
|
10
|
+
import type {
|
|
11
|
+
Agent,
|
|
12
|
+
CreateAgentInput,
|
|
13
|
+
UpdateAgentInput,
|
|
14
|
+
AgentHandlers,
|
|
15
|
+
} from '../../handlers/agent.handlers';
|
|
16
|
+
|
|
17
|
+
export interface MutationState<T> {
|
|
18
|
+
loading: boolean;
|
|
19
|
+
error: Error | null;
|
|
20
|
+
data: T | null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface UseAgentMutationsOptions {
|
|
24
|
+
onSuccess?: () => void;
|
|
25
|
+
onError?: (error: Error) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function useAgentMutations(options: UseAgentMutationsOptions = {}) {
|
|
29
|
+
const { handlers, projectId } = useTemplateRuntime<{
|
|
30
|
+
agent: AgentHandlers;
|
|
31
|
+
}>();
|
|
32
|
+
const { agent } = handlers;
|
|
33
|
+
|
|
34
|
+
const [createState, setCreateState] = useState<MutationState<Agent>>({
|
|
35
|
+
loading: false,
|
|
36
|
+
error: null,
|
|
37
|
+
data: null,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const [updateState, setUpdateState] = useState<MutationState<Agent>>({
|
|
41
|
+
loading: false,
|
|
42
|
+
error: null,
|
|
43
|
+
data: null,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Create a new agent
|
|
48
|
+
*/
|
|
49
|
+
const createAgent = useCallback(
|
|
50
|
+
async (input: CreateAgentInput): Promise<Agent | null> => {
|
|
51
|
+
setCreateState({ loading: true, error: null, data: null });
|
|
52
|
+
try {
|
|
53
|
+
const result = await agent.createAgent(input, {
|
|
54
|
+
projectId,
|
|
55
|
+
organizationId: 'demo-org',
|
|
56
|
+
});
|
|
57
|
+
setCreateState({ loading: false, error: null, data: result });
|
|
58
|
+
options.onSuccess?.();
|
|
59
|
+
return result;
|
|
60
|
+
} catch (err) {
|
|
61
|
+
const error =
|
|
62
|
+
err instanceof Error ? err : new Error('Failed to create agent');
|
|
63
|
+
setCreateState({ loading: false, error, data: null });
|
|
64
|
+
options.onError?.(error);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
[agent, projectId, options]
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Update an agent (name, status)
|
|
73
|
+
*/
|
|
74
|
+
const updateAgent = useCallback(
|
|
75
|
+
async (input: UpdateAgentInput): Promise<Agent | null> => {
|
|
76
|
+
setUpdateState({ loading: true, error: null, data: null });
|
|
77
|
+
try {
|
|
78
|
+
const result = await agent.updateAgent(input);
|
|
79
|
+
setUpdateState({ loading: false, error: null, data: result });
|
|
80
|
+
options.onSuccess?.();
|
|
81
|
+
return result;
|
|
82
|
+
} catch (err) {
|
|
83
|
+
const error =
|
|
84
|
+
err instanceof Error ? err : new Error('Failed to update agent');
|
|
85
|
+
setUpdateState({ loading: false, error, data: null });
|
|
86
|
+
options.onError?.(error);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
[agent, options]
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Activate an agent
|
|
95
|
+
*/
|
|
96
|
+
const activateAgent = useCallback(
|
|
97
|
+
async (agentId: string): Promise<Agent | null> => {
|
|
98
|
+
return updateAgent({ id: agentId, status: 'ACTIVE' });
|
|
99
|
+
},
|
|
100
|
+
[updateAgent]
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Pause an agent
|
|
105
|
+
*/
|
|
106
|
+
const pauseAgent = useCallback(
|
|
107
|
+
async (agentId: string): Promise<Agent | null> => {
|
|
108
|
+
return updateAgent({ id: agentId, status: 'PAUSED' });
|
|
109
|
+
},
|
|
110
|
+
[updateAgent]
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Archive an agent
|
|
115
|
+
*/
|
|
116
|
+
const archiveAgent = useCallback(
|
|
117
|
+
async (agentId: string): Promise<Agent | null> => {
|
|
118
|
+
return updateAgent({ id: agentId, status: 'ARCHIVED' });
|
|
119
|
+
},
|
|
120
|
+
[updateAgent]
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Execute an agent (placeholder - needs run handler)
|
|
125
|
+
* Note: Execute functionality requires adding createRun/executeRun to agent handlers
|
|
126
|
+
*/
|
|
127
|
+
const executeAgent = useCallback(
|
|
128
|
+
async (input: { agentId: string; message: string }): Promise<null> => {
|
|
129
|
+
// TODO: Implement execute when run creation handler is added to runtime-local
|
|
130
|
+
console.log('Execute agent:', input);
|
|
131
|
+
options.onSuccess?.();
|
|
132
|
+
return null;
|
|
133
|
+
},
|
|
134
|
+
[options]
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
// Mutations
|
|
139
|
+
createAgent,
|
|
140
|
+
updateAgent,
|
|
141
|
+
activateAgent,
|
|
142
|
+
pauseAgent,
|
|
143
|
+
archiveAgent,
|
|
144
|
+
executeAgent,
|
|
145
|
+
|
|
146
|
+
// State
|
|
147
|
+
createState,
|
|
148
|
+
updateState,
|
|
149
|
+
|
|
150
|
+
// Convenience
|
|
151
|
+
isLoading: createState.loading || updateState.loading,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Re-export types for convenience
|
|
156
|
+
export type { CreateAgentInput, UpdateAgentInput, Agent };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for fetching and managing run list data
|
|
3
|
+
*
|
|
4
|
+
* Uses runtime-local database-backed handlers.
|
|
5
|
+
*/
|
|
6
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
7
|
+
import { useTemplateRuntime } from '@contractspec/lib.example-shared-ui';
|
|
8
|
+
import type {
|
|
9
|
+
ListRunsOutput as RuntimeListRunsOutput,
|
|
10
|
+
Run as RuntimeRun,
|
|
11
|
+
RunMetrics as RuntimeRunMetrics,
|
|
12
|
+
AgentHandlers,
|
|
13
|
+
} from '../../handlers/agent.handlers';
|
|
14
|
+
|
|
15
|
+
// Re-export types for convenience
|
|
16
|
+
export type Run = RuntimeRun;
|
|
17
|
+
export type ListRunsOutput = RuntimeListRunsOutput;
|
|
18
|
+
export type RunMetrics = RuntimeRunMetrics;
|
|
19
|
+
|
|
20
|
+
export interface UseRunListOptions {
|
|
21
|
+
agentId?: string;
|
|
22
|
+
status?: Run['status'] | 'all';
|
|
23
|
+
limit?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function useRunList(options: UseRunListOptions = {}) {
|
|
27
|
+
const { handlers, projectId } = useTemplateRuntime<{
|
|
28
|
+
agent: AgentHandlers;
|
|
29
|
+
}>();
|
|
30
|
+
const { agent } = handlers;
|
|
31
|
+
|
|
32
|
+
const [data, setData] = useState<ListRunsOutput | null>(null);
|
|
33
|
+
const [metrics, setMetrics] = useState<RunMetrics | null>(null);
|
|
34
|
+
const [loading, setLoading] = useState(true);
|
|
35
|
+
const [error, setError] = useState<Error | null>(null);
|
|
36
|
+
const [page, setPage] = useState(1);
|
|
37
|
+
|
|
38
|
+
const fetchData = useCallback(async () => {
|
|
39
|
+
setLoading(true);
|
|
40
|
+
setError(null);
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const [runsResult, metricsResult] = await Promise.all([
|
|
44
|
+
agent.listRuns({
|
|
45
|
+
projectId,
|
|
46
|
+
agentId: options.agentId,
|
|
47
|
+
status: options.status === 'all' ? undefined : options.status,
|
|
48
|
+
limit: options.limit ?? 20,
|
|
49
|
+
offset: (page - 1) * (options.limit ?? 20),
|
|
50
|
+
}),
|
|
51
|
+
agent.getRunMetrics({
|
|
52
|
+
projectId,
|
|
53
|
+
agentId: options.agentId,
|
|
54
|
+
startDate: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), // 30 days ago
|
|
55
|
+
endDate: new Date(),
|
|
56
|
+
}),
|
|
57
|
+
]);
|
|
58
|
+
setData(runsResult);
|
|
59
|
+
setMetrics(metricsResult);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
setError(err instanceof Error ? err : new Error('Unknown error'));
|
|
62
|
+
} finally {
|
|
63
|
+
setLoading(false);
|
|
64
|
+
}
|
|
65
|
+
}, [agent, projectId, options.agentId, options.status, options.limit, page]);
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
fetchData();
|
|
69
|
+
}, [fetchData]);
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
data,
|
|
73
|
+
metrics,
|
|
74
|
+
loading,
|
|
75
|
+
error,
|
|
76
|
+
page,
|
|
77
|
+
refetch: fetchData,
|
|
78
|
+
nextPage: () => setPage((p) => p + 1),
|
|
79
|
+
prevPage: () => page > 1 && setPage((p) => p - 1),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for fetching and managing tool list data
|
|
3
|
+
*
|
|
4
|
+
* Uses runtime-local database-backed handlers.
|
|
5
|
+
*/
|
|
6
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
7
|
+
import { useTemplateRuntime } from '@contractspec/lib.example-shared-ui';
|
|
8
|
+
import type {
|
|
9
|
+
ListToolsOutput as RuntimeListToolsOutput,
|
|
10
|
+
Tool as RuntimeTool,
|
|
11
|
+
AgentHandlers,
|
|
12
|
+
} from '../../handlers/agent.handlers';
|
|
13
|
+
|
|
14
|
+
// Re-export types for convenience
|
|
15
|
+
export type Tool = RuntimeTool;
|
|
16
|
+
export type ListToolsOutput = RuntimeListToolsOutput;
|
|
17
|
+
|
|
18
|
+
export type ToolCategory = Tool['category'];
|
|
19
|
+
export type ToolStatus = Tool['status'];
|
|
20
|
+
|
|
21
|
+
export interface UseToolListOptions {
|
|
22
|
+
search?: string;
|
|
23
|
+
category?: ToolCategory;
|
|
24
|
+
status?: ToolStatus | 'all';
|
|
25
|
+
limit?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function useToolList(options: UseToolListOptions = {}) {
|
|
29
|
+
const { handlers, projectId } = useTemplateRuntime<{
|
|
30
|
+
agent: AgentHandlers;
|
|
31
|
+
}>();
|
|
32
|
+
const { agent } = handlers;
|
|
33
|
+
|
|
34
|
+
const [data, setData] = useState<ListToolsOutput | null>(null);
|
|
35
|
+
const [loading, setLoading] = useState(true);
|
|
36
|
+
const [error, setError] = useState<Error | null>(null);
|
|
37
|
+
const [page, setPage] = useState(1);
|
|
38
|
+
|
|
39
|
+
const fetchData = useCallback(async () => {
|
|
40
|
+
setLoading(true);
|
|
41
|
+
setError(null);
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const result = await agent.listTools({
|
|
45
|
+
projectId,
|
|
46
|
+
search: options.search,
|
|
47
|
+
category: options.category,
|
|
48
|
+
status: options.status === 'all' ? undefined : options.status,
|
|
49
|
+
limit: options.limit ?? 50,
|
|
50
|
+
offset: (page - 1) * (options.limit ?? 50),
|
|
51
|
+
});
|
|
52
|
+
setData(result);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
setError(err instanceof Error ? err : new Error('Unknown error'));
|
|
55
|
+
} finally {
|
|
56
|
+
setLoading(false);
|
|
57
|
+
}
|
|
58
|
+
}, [
|
|
59
|
+
agent,
|
|
60
|
+
projectId,
|
|
61
|
+
options.search,
|
|
62
|
+
options.category,
|
|
63
|
+
options.status,
|
|
64
|
+
options.limit,
|
|
65
|
+
page,
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
fetchData();
|
|
70
|
+
}, [fetchData]);
|
|
71
|
+
|
|
72
|
+
// Calculate stats and grouping
|
|
73
|
+
const { stats, groupedByCategory, categoryStats } = useMemo(() => {
|
|
74
|
+
if (!data) return { stats: null, groupedByCategory: {}, categoryStats: [] };
|
|
75
|
+
const items = data.items;
|
|
76
|
+
|
|
77
|
+
const active = items.filter((t) => t.status === 'ACTIVE').length;
|
|
78
|
+
const deprecated = items.filter((t) => t.status === 'DEPRECATED').length;
|
|
79
|
+
const disabled = items.filter((t) => t.status === 'DISABLED').length;
|
|
80
|
+
|
|
81
|
+
// Group by category
|
|
82
|
+
const grouped: Record<string, Tool[]> = {};
|
|
83
|
+
const byCategory: Record<string, number> = {};
|
|
84
|
+
|
|
85
|
+
items.forEach((t) => {
|
|
86
|
+
const cat = t.category;
|
|
87
|
+
if (!grouped[cat]) grouped[cat] = [];
|
|
88
|
+
grouped[cat].push(t);
|
|
89
|
+
byCategory[cat] = (byCategory[cat] || 0) + 1;
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Category stats sorted by count
|
|
93
|
+
const catStats = Object.entries(byCategory)
|
|
94
|
+
.map(([category, count]) => ({ category, count }))
|
|
95
|
+
.sort((a, b) => b.count - a.count);
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
stats: {
|
|
99
|
+
total: data.total,
|
|
100
|
+
active,
|
|
101
|
+
deprecated,
|
|
102
|
+
disabled,
|
|
103
|
+
topCategories: catStats.slice(0, 5),
|
|
104
|
+
},
|
|
105
|
+
groupedByCategory: grouped,
|
|
106
|
+
categoryStats: catStats,
|
|
107
|
+
};
|
|
108
|
+
}, [data]);
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
data,
|
|
112
|
+
loading,
|
|
113
|
+
error,
|
|
114
|
+
stats,
|
|
115
|
+
groupedByCategory,
|
|
116
|
+
categoryStats,
|
|
117
|
+
page,
|
|
118
|
+
refetch: fetchData,
|
|
119
|
+
nextPage: () => setPage((p) => p + 1),
|
|
120
|
+
prevPage: () => page > 1 && setPage((p) => p - 1),
|
|
121
|
+
};
|
|
122
|
+
}
|
package/src/ui/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Main dashboard component
|
|
2
|
+
export * from './AgentDashboard';
|
|
3
|
+
|
|
4
|
+
// Backward-compatible exports
|
|
5
|
+
export * from './AgentRunList';
|
|
6
|
+
export * from './AgentToolRegistry';
|
|
7
|
+
|
|
8
|
+
// View components
|
|
9
|
+
export * from './views';
|
|
10
|
+
|
|
11
|
+
// Modals
|
|
12
|
+
export * from './modals';
|
|
13
|
+
|
|
14
|
+
// Data hooks
|
|
15
|
+
export * from './hooks';
|
|
16
|
+
|
|
17
|
+
// Renderers
|
|
18
|
+
export * from './renderers';
|
|
19
|
+
|
|
20
|
+
// Overlays
|
|
21
|
+
export * from './overlays';
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AgentActionsModal - Actions for a specific agent
|
|
5
|
+
*
|
|
6
|
+
* Wires to UpdateAgentCommand via useAgentMutations hook.
|
|
7
|
+
*/
|
|
8
|
+
import { useState } from 'react';
|
|
9
|
+
import { Button } from '@contractspec/lib.design-system';
|
|
10
|
+
import type { Agent } from '../hooks/useAgentList';
|
|
11
|
+
|
|
12
|
+
type ActionMode = 'menu' | 'execute' | 'confirm';
|
|
13
|
+
|
|
14
|
+
interface AgentActionsModalProps {
|
|
15
|
+
isOpen: boolean;
|
|
16
|
+
agent: Agent | null;
|
|
17
|
+
onClose: () => void;
|
|
18
|
+
onActivate: (agentId: string) => Promise<void>;
|
|
19
|
+
onPause: (agentId: string) => Promise<void>;
|
|
20
|
+
onArchive: (agentId: string) => Promise<void>;
|
|
21
|
+
onExecute: (agentId: string, message: string) => Promise<void>;
|
|
22
|
+
isLoading?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getStatusColor(status: Agent['status']): string {
|
|
26
|
+
switch (status) {
|
|
27
|
+
case 'ACTIVE':
|
|
28
|
+
return 'text-green-600 bg-green-100 dark:text-green-400 dark:bg-green-900/30';
|
|
29
|
+
case 'DRAFT':
|
|
30
|
+
return 'text-blue-600 bg-blue-100 dark:text-blue-400 dark:bg-blue-900/30';
|
|
31
|
+
case 'PAUSED':
|
|
32
|
+
return 'text-yellow-600 bg-yellow-100 dark:text-yellow-400 dark:bg-yellow-900/30';
|
|
33
|
+
case 'ARCHIVED':
|
|
34
|
+
return 'text-gray-600 bg-gray-100 dark:text-gray-400 dark:bg-gray-700';
|
|
35
|
+
default:
|
|
36
|
+
return 'text-gray-600 bg-gray-100';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function AgentActionsModal({
|
|
41
|
+
isOpen,
|
|
42
|
+
agent,
|
|
43
|
+
onClose,
|
|
44
|
+
onActivate,
|
|
45
|
+
onPause,
|
|
46
|
+
onArchive,
|
|
47
|
+
onExecute,
|
|
48
|
+
isLoading = false,
|
|
49
|
+
}: AgentActionsModalProps) {
|
|
50
|
+
const [mode, setMode] = useState<ActionMode>('menu');
|
|
51
|
+
const [message, setMessage] = useState('');
|
|
52
|
+
const [confirmAction, setConfirmAction] = useState<'archive' | null>(null);
|
|
53
|
+
const [error, setError] = useState<string | null>(null);
|
|
54
|
+
|
|
55
|
+
const resetForm = () => {
|
|
56
|
+
setMode('menu');
|
|
57
|
+
setMessage('');
|
|
58
|
+
setConfirmAction(null);
|
|
59
|
+
setError(null);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const handleClose = () => {
|
|
63
|
+
resetForm();
|
|
64
|
+
onClose();
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const handleExecute = async () => {
|
|
68
|
+
if (!agent) return;
|
|
69
|
+
setError(null);
|
|
70
|
+
|
|
71
|
+
if (!message.trim()) {
|
|
72
|
+
setError('Please enter a message');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
await onExecute(agent.id, message.trim());
|
|
78
|
+
handleClose();
|
|
79
|
+
} catch (err) {
|
|
80
|
+
setError(err instanceof Error ? err.message : 'Failed to execute agent');
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const handleStatusChange = async (
|
|
85
|
+
action: 'activate' | 'pause' | 'archive'
|
|
86
|
+
) => {
|
|
87
|
+
if (!agent) return;
|
|
88
|
+
setError(null);
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
switch (action) {
|
|
92
|
+
case 'activate':
|
|
93
|
+
await onActivate(agent.id);
|
|
94
|
+
break;
|
|
95
|
+
case 'pause':
|
|
96
|
+
await onPause(agent.id);
|
|
97
|
+
break;
|
|
98
|
+
case 'archive':
|
|
99
|
+
await onArchive(agent.id);
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
handleClose();
|
|
103
|
+
} catch (err) {
|
|
104
|
+
setError(
|
|
105
|
+
err instanceof Error ? err.message : `Failed to ${action} agent`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
if (!isOpen || !agent) return null;
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
|
114
|
+
{/* Backdrop */}
|
|
115
|
+
<div
|
|
116
|
+
className="bg-background/80 absolute inset-0 backdrop-blur-sm"
|
|
117
|
+
onClick={handleClose}
|
|
118
|
+
role="button"
|
|
119
|
+
tabIndex={0}
|
|
120
|
+
onKeyDown={(e) => {
|
|
121
|
+
if (e.key === 'Enter' || e.key === ' ') handleClose();
|
|
122
|
+
}}
|
|
123
|
+
aria-label="Close modal"
|
|
124
|
+
/>
|
|
125
|
+
|
|
126
|
+
{/* Modal */}
|
|
127
|
+
<div className="bg-card border-border relative z-10 w-full max-w-md rounded-xl border p-6 shadow-xl">
|
|
128
|
+
{/* Agent Header */}
|
|
129
|
+
<div className="border-border mb-4 border-b pb-4">
|
|
130
|
+
<h2 className="text-xl font-semibold">{agent.name}</h2>
|
|
131
|
+
<div className="mt-1 flex items-center gap-2">
|
|
132
|
+
<span className="text-muted-foreground text-sm">
|
|
133
|
+
{agent.modelProvider} / {agent.modelName}
|
|
134
|
+
</span>
|
|
135
|
+
<span
|
|
136
|
+
className={`rounded-full px-2 py-0.5 text-xs font-medium ${getStatusColor(agent.status)}`}
|
|
137
|
+
>
|
|
138
|
+
{agent.status}
|
|
139
|
+
</span>
|
|
140
|
+
</div>
|
|
141
|
+
{agent.description && (
|
|
142
|
+
<p className="text-muted-foreground mt-2 text-sm">
|
|
143
|
+
{agent.description}
|
|
144
|
+
</p>
|
|
145
|
+
)}
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
{/* Main Menu */}
|
|
149
|
+
{mode === 'menu' && (
|
|
150
|
+
<div className="space-y-3">
|
|
151
|
+
{/* Execute - Only for active agents */}
|
|
152
|
+
{agent.status === 'ACTIVE' && (
|
|
153
|
+
<Button
|
|
154
|
+
className="w-full justify-start"
|
|
155
|
+
variant="ghost"
|
|
156
|
+
onPress={() => setMode('execute')}
|
|
157
|
+
>
|
|
158
|
+
<span className="mr-2">▶️</span> Execute Agent
|
|
159
|
+
</Button>
|
|
160
|
+
)}
|
|
161
|
+
|
|
162
|
+
{/* Status Changes */}
|
|
163
|
+
{(agent.status === 'DRAFT' || agent.status === 'PAUSED') && (
|
|
164
|
+
<Button
|
|
165
|
+
className="w-full justify-start"
|
|
166
|
+
variant="ghost"
|
|
167
|
+
onPress={() => handleStatusChange('activate')}
|
|
168
|
+
disabled={isLoading}
|
|
169
|
+
>
|
|
170
|
+
<span className="mr-2">🟢</span> Activate Agent
|
|
171
|
+
</Button>
|
|
172
|
+
)}
|
|
173
|
+
|
|
174
|
+
{agent.status === 'ACTIVE' && (
|
|
175
|
+
<Button
|
|
176
|
+
className="w-full justify-start"
|
|
177
|
+
variant="ghost"
|
|
178
|
+
onPress={() => handleStatusChange('pause')}
|
|
179
|
+
disabled={isLoading}
|
|
180
|
+
>
|
|
181
|
+
<span className="mr-2">⏸️</span> Pause Agent
|
|
182
|
+
</Button>
|
|
183
|
+
)}
|
|
184
|
+
|
|
185
|
+
{agent.status !== 'ARCHIVED' && (
|
|
186
|
+
<Button
|
|
187
|
+
className="w-full justify-start text-yellow-600 hover:text-yellow-700"
|
|
188
|
+
variant="ghost"
|
|
189
|
+
onPress={() => {
|
|
190
|
+
setConfirmAction('archive');
|
|
191
|
+
setMode('confirm');
|
|
192
|
+
}}
|
|
193
|
+
>
|
|
194
|
+
<span className="mr-2">📦</span> Archive Agent
|
|
195
|
+
</Button>
|
|
196
|
+
)}
|
|
197
|
+
|
|
198
|
+
{agent.status === 'ARCHIVED' && (
|
|
199
|
+
<Button
|
|
200
|
+
className="w-full justify-start"
|
|
201
|
+
variant="ghost"
|
|
202
|
+
onPress={() => handleStatusChange('activate')}
|
|
203
|
+
disabled={isLoading}
|
|
204
|
+
>
|
|
205
|
+
<span className="mr-2">🔄</span> Restore Agent
|
|
206
|
+
</Button>
|
|
207
|
+
)}
|
|
208
|
+
|
|
209
|
+
{error && (
|
|
210
|
+
<div className="bg-destructive/10 text-destructive rounded-md p-3 text-sm">
|
|
211
|
+
{error}
|
|
212
|
+
</div>
|
|
213
|
+
)}
|
|
214
|
+
|
|
215
|
+
<div className="border-border border-t pt-3">
|
|
216
|
+
<Button
|
|
217
|
+
className="w-full"
|
|
218
|
+
variant="outline"
|
|
219
|
+
onPress={handleClose}
|
|
220
|
+
>
|
|
221
|
+
Close
|
|
222
|
+
</Button>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
)}
|
|
226
|
+
|
|
227
|
+
{/* Execute Form */}
|
|
228
|
+
{mode === 'execute' && (
|
|
229
|
+
<div className="space-y-4">
|
|
230
|
+
<div>
|
|
231
|
+
<label
|
|
232
|
+
htmlFor="execute-message"
|
|
233
|
+
className="text-muted-foreground mb-1 block text-sm font-medium"
|
|
234
|
+
>
|
|
235
|
+
Message *
|
|
236
|
+
</label>
|
|
237
|
+
<textarea
|
|
238
|
+
id="execute-message"
|
|
239
|
+
value={message}
|
|
240
|
+
onChange={(e) => setMessage(e.target.value)}
|
|
241
|
+
placeholder="Enter your message to the agent..."
|
|
242
|
+
rows={4}
|
|
243
|
+
disabled={isLoading}
|
|
244
|
+
className="border-input bg-background focus:ring-ring w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none disabled:opacity-50"
|
|
245
|
+
/>
|
|
246
|
+
</div>
|
|
247
|
+
|
|
248
|
+
{error && (
|
|
249
|
+
<div className="bg-destructive/10 text-destructive rounded-md p-3 text-sm">
|
|
250
|
+
{error}
|
|
251
|
+
</div>
|
|
252
|
+
)}
|
|
253
|
+
|
|
254
|
+
<div className="flex justify-end gap-3 pt-2">
|
|
255
|
+
<Button
|
|
256
|
+
variant="ghost"
|
|
257
|
+
onPress={() => setMode('menu')}
|
|
258
|
+
disabled={isLoading}
|
|
259
|
+
>
|
|
260
|
+
Back
|
|
261
|
+
</Button>
|
|
262
|
+
<Button onPress={handleExecute} disabled={isLoading}>
|
|
263
|
+
{isLoading ? 'Executing...' : '▶️ Execute'}
|
|
264
|
+
</Button>
|
|
265
|
+
</div>
|
|
266
|
+
</div>
|
|
267
|
+
)}
|
|
268
|
+
|
|
269
|
+
{/* Confirm Action */}
|
|
270
|
+
{mode === 'confirm' && confirmAction === 'archive' && (
|
|
271
|
+
<div className="space-y-4">
|
|
272
|
+
<p className="text-muted-foreground">
|
|
273
|
+
Are you sure you want to archive{' '}
|
|
274
|
+
<span className="text-foreground font-medium">{agent.name}</span>?
|
|
275
|
+
</p>
|
|
276
|
+
<p className="text-muted-foreground text-sm">
|
|
277
|
+
Archived agents cannot be executed but can be restored later.
|
|
278
|
+
</p>
|
|
279
|
+
|
|
280
|
+
{error && (
|
|
281
|
+
<div className="bg-destructive/10 text-destructive rounded-md p-3 text-sm">
|
|
282
|
+
{error}
|
|
283
|
+
</div>
|
|
284
|
+
)}
|
|
285
|
+
|
|
286
|
+
<div className="flex justify-end gap-3 pt-2">
|
|
287
|
+
<Button
|
|
288
|
+
variant="ghost"
|
|
289
|
+
onPress={() => setMode('menu')}
|
|
290
|
+
disabled={isLoading}
|
|
291
|
+
>
|
|
292
|
+
Cancel
|
|
293
|
+
</Button>
|
|
294
|
+
<Button
|
|
295
|
+
onPress={() => handleStatusChange('archive')}
|
|
296
|
+
disabled={isLoading}
|
|
297
|
+
>
|
|
298
|
+
{isLoading ? 'Archiving...' : '📦 Archive'}
|
|
299
|
+
</Button>
|
|
300
|
+
</div>
|
|
301
|
+
</div>
|
|
302
|
+
)}
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
);
|
|
306
|
+
}
|