@hashgraphonline/conversational-agent 0.1.210 → 0.1.213

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 (55) hide show
  1. package/cli/dist/CLIApp.d.ts +9 -0
  2. package/cli/dist/CLIApp.js +127 -0
  3. package/cli/dist/LocalConversationalAgent.d.ts +37 -0
  4. package/cli/dist/LocalConversationalAgent.js +58 -0
  5. package/cli/dist/app.d.ts +16 -0
  6. package/cli/dist/app.js +13 -0
  7. package/cli/dist/cli.d.ts +2 -0
  8. package/cli/dist/cli.js +51 -0
  9. package/cli/dist/components/AppContainer.d.ts +16 -0
  10. package/cli/dist/components/AppContainer.js +24 -0
  11. package/cli/dist/components/AppScreens.d.ts +2 -0
  12. package/cli/dist/components/AppScreens.js +259 -0
  13. package/cli/dist/components/ChatScreen.d.ts +15 -0
  14. package/cli/dist/components/ChatScreen.js +39 -0
  15. package/cli/dist/components/DebugLoadingScreen.d.ts +5 -0
  16. package/cli/dist/components/DebugLoadingScreen.js +31 -0
  17. package/cli/dist/components/LoadingScreen.d.ts +2 -0
  18. package/cli/dist/components/LoadingScreen.js +16 -0
  19. package/cli/dist/components/LoadingScreenDebug.d.ts +5 -0
  20. package/cli/dist/components/LoadingScreenDebug.js +27 -0
  21. package/cli/dist/components/MCPConfigScreen.d.ts +28 -0
  22. package/cli/dist/components/MCPConfigScreen.js +168 -0
  23. package/cli/dist/components/ScreenRouter.d.ts +12 -0
  24. package/cli/dist/components/ScreenRouter.js +22 -0
  25. package/cli/dist/components/SetupScreen.d.ts +15 -0
  26. package/cli/dist/components/SetupScreen.js +65 -0
  27. package/cli/dist/components/SingleLoadingScreen.d.ts +5 -0
  28. package/cli/dist/components/SingleLoadingScreen.js +27 -0
  29. package/cli/dist/components/StatusBadge.d.ts +7 -0
  30. package/cli/dist/components/StatusBadge.js +28 -0
  31. package/cli/dist/components/TerminalWindow.d.ts +8 -0
  32. package/cli/dist/components/TerminalWindow.js +24 -0
  33. package/cli/dist/components/WelcomeScreen.d.ts +11 -0
  34. package/cli/dist/components/WelcomeScreen.js +47 -0
  35. package/cli/dist/context/AppContext.d.ts +68 -0
  36. package/cli/dist/context/AppContext.js +363 -0
  37. package/cli/dist/hooks/useInitializeAgent.d.ts +19 -0
  38. package/cli/dist/hooks/useInitializeAgent.js +28 -0
  39. package/cli/dist/hooks/useStableState.d.ts +38 -0
  40. package/cli/dist/hooks/useStableState.js +68 -0
  41. package/cli/dist/managers/AgentManager.d.ts +57 -0
  42. package/cli/dist/managers/AgentManager.js +119 -0
  43. package/cli/dist/managers/ConfigManager.d.ts +53 -0
  44. package/cli/dist/managers/ConfigManager.js +173 -0
  45. package/cli/dist/types.d.ts +31 -0
  46. package/cli/dist/types.js +19 -0
  47. package/dist/cjs/conversational-agent.d.ts +1 -9
  48. package/dist/cjs/index.cjs +1 -1
  49. package/dist/cjs/index.cjs.map +1 -1
  50. package/dist/esm/index6.js +11 -25
  51. package/dist/esm/index6.js.map +1 -1
  52. package/dist/types/conversational-agent.d.ts +1 -9
  53. package/package.json +27 -29
  54. package/src/conversational-agent.ts +15 -31
  55. package/cli/readme.md +0 -181
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+ import { ConversationalAgent, type MCPServerConfig } from '@hashgraphonline/conversational-agent';
3
+ import { type Screen, type Message, type Config } from '../types.js';
4
+ interface AppState {
5
+ screen: Screen;
6
+ agent: ConversationalAgent | null;
7
+ messages: Message[];
8
+ input: string;
9
+ isLoading: boolean;
10
+ error: string | null;
11
+ config: Config & {
12
+ mcpServers: MCPServerConfig[];
13
+ };
14
+ mcpConfig: {
15
+ enableFilesystem: boolean;
16
+ filesystemPath: string;
17
+ customServers: MCPServerConfig[];
18
+ addingCustom: boolean;
19
+ newServerName: string;
20
+ newServerCommand: string;
21
+ newServerArgs: string;
22
+ newServerEnv: string;
23
+ currentField: number;
24
+ };
25
+ editingFilesystemPath: boolean;
26
+ currentField: number;
27
+ logs: string[];
28
+ }
29
+ interface AppContextType {
30
+ state: AppState;
31
+ actions: {
32
+ setScreen: (screen: Screen) => void;
33
+ setAgent: (agent: ConversationalAgent | null) => void;
34
+ setMessages: (messages: Message[]) => void;
35
+ addMessages: (messages: Message[]) => void;
36
+ setInput: (input: string) => void;
37
+ setLoading: (loading: boolean) => void;
38
+ setError: (error: string | null) => void;
39
+ setConfig: (config: Config & {
40
+ mcpServers: MCPServerConfig[];
41
+ }) => void;
42
+ updateConfigField: (field: keyof Config, value: string) => void;
43
+ setMcpConfig: (config: Partial<AppState['mcpConfig']>) => void;
44
+ setEditingFilesystemPath: (editing: boolean) => void;
45
+ setCurrentField: (field: number) => void;
46
+ setLogs: (logs: string[]) => void;
47
+ initializeAgent: () => Promise<void>;
48
+ sendMessage: (message: string) => Promise<void>;
49
+ };
50
+ }
51
+ /**
52
+ * Get MCP config file path
53
+ */
54
+ declare const getMCPConfigPath: () => string;
55
+ /**
56
+ * Save MCP configuration to file
57
+ */
58
+ declare const saveMCPConfig: (servers: MCPServerConfig[]) => void;
59
+ interface AppProviderProps {
60
+ children: React.ReactNode;
61
+ accountId?: string;
62
+ privateKey?: string;
63
+ network?: 'testnet' | 'mainnet';
64
+ openAIApiKey?: string;
65
+ }
66
+ export declare const AppProvider: React.FC<AppProviderProps>;
67
+ export declare const useAppContext: () => AppContextType;
68
+ export { saveMCPConfig, getMCPConfigPath };
@@ -0,0 +1,363 @@
1
+ import React, { createContext, useContext, useReducer, useCallback, useRef, useEffect } from 'react';
2
+ import { ConversationalAgent, MCPServers } from '@hashgraphonline/conversational-agent';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ const AppContext = createContext(null);
6
+ /**
7
+ * Get MCP config file path
8
+ */
9
+ const getMCPConfigPath = () => {
10
+ const projectRoot = process.env['CONVERSATIONAL_AGENT_ROOT'] || path.resolve('./../../');
11
+ return path.join(projectRoot, 'mcp-config.json');
12
+ };
13
+ /**
14
+ * Load MCP configuration from file
15
+ */
16
+ const loadMCPConfig = () => {
17
+ const configPath = getMCPConfigPath();
18
+ try {
19
+ if (fs.existsSync(configPath)) {
20
+ const configContent = fs.readFileSync(configPath, 'utf-8');
21
+ const config = JSON.parse(configContent);
22
+ return Object.values(config.mcpServers || {});
23
+ }
24
+ }
25
+ catch (err) {
26
+ console.error('Failed to load MCP config:', err);
27
+ }
28
+ const defaultServers = [MCPServers.filesystem(process.cwd())];
29
+ saveMCPConfig(defaultServers);
30
+ return defaultServers;
31
+ };
32
+ /**
33
+ * Save MCP configuration to file
34
+ */
35
+ const saveMCPConfig = (servers) => {
36
+ const configPath = getMCPConfigPath();
37
+ try {
38
+ const mcpServers = {};
39
+ servers.forEach(server => {
40
+ mcpServers[server.name] = server;
41
+ });
42
+ const config = { mcpServers };
43
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
44
+ }
45
+ catch (err) {
46
+ console.error('Failed to save MCP config:', err);
47
+ }
48
+ };
49
+ /**
50
+ * Load config from .env file
51
+ */
52
+ const loadConfigFromEnv = () => {
53
+ const projectRoot = process.env['CONVERSATIONAL_AGENT_ROOT'] || path.resolve('./../../');
54
+ const envPath = path.join(projectRoot, '.env');
55
+ try {
56
+ if (fs.existsSync(envPath)) {
57
+ const envContent = fs.readFileSync(envPath, 'utf-8');
58
+ const envVars = {};
59
+ envContent.split('\n').forEach(line => {
60
+ const trimmedLine = line.trim();
61
+ if (trimmedLine && !trimmedLine.startsWith('#')) {
62
+ const [key, ...valueParts] = trimmedLine.split('=');
63
+ if (key && valueParts.length > 0) {
64
+ envVars[key] = valueParts.join('=');
65
+ }
66
+ }
67
+ });
68
+ return {
69
+ accountId: envVars['HEDERA_ACCOUNT_ID'] || '',
70
+ privateKey: envVars['HEDERA_PRIVATE_KEY'] || '',
71
+ network: envVars['HEDERA_NETWORK'] || 'testnet',
72
+ openAIApiKey: envVars['OPENAI_API_KEY'] || '',
73
+ mcpServers: envVars['MCP_SERVERS'] ? JSON.parse(envVars['MCP_SERVERS']) : [],
74
+ };
75
+ }
76
+ }
77
+ catch (err) { }
78
+ return {
79
+ accountId: '',
80
+ privateKey: '',
81
+ network: 'testnet',
82
+ openAIApiKey: '',
83
+ mcpServers: [],
84
+ };
85
+ };
86
+ /**
87
+ * Save config to .env file
88
+ */
89
+ const saveConfig = (configToSave) => {
90
+ const projectRoot = process.env['CONVERSATIONAL_AGENT_ROOT'] || path.resolve('./../../');
91
+ const envPath = path.join(projectRoot, '.env');
92
+ try {
93
+ let envContent = '';
94
+ if (fs.existsSync(envPath)) {
95
+ envContent = fs.readFileSync(envPath, 'utf-8');
96
+ }
97
+ const updateEnvVar = (key, value) => {
98
+ const regex = new RegExp(`^${key}=.*$`, 'gm');
99
+ if (regex.test(envContent)) {
100
+ envContent = envContent.replace(regex, `${key}=${value}`);
101
+ }
102
+ else {
103
+ envContent += `${envContent ? '\n' : ''}${key}=${value}`;
104
+ }
105
+ };
106
+ updateEnvVar('HEDERA_ACCOUNT_ID', configToSave.accountId);
107
+ updateEnvVar('HEDERA_PRIVATE_KEY', configToSave.privateKey);
108
+ updateEnvVar('HEDERA_NETWORK', configToSave.network);
109
+ updateEnvVar('OPENAI_API_KEY', configToSave.openAIApiKey);
110
+ updateEnvVar('MCP_SERVERS', JSON.stringify(configToSave.mcpServers || []));
111
+ fs.writeFileSync(envPath, envContent);
112
+ }
113
+ catch (err) { }
114
+ };
115
+ const appReducer = (state, action) => {
116
+ switch (action.type) {
117
+ case 'SET_SCREEN':
118
+ return { ...state, screen: action.payload };
119
+ case 'SET_AGENT':
120
+ return { ...state, agent: action.payload };
121
+ case 'SET_MESSAGES':
122
+ return { ...state, messages: action.payload };
123
+ case 'ADD_MESSAGES':
124
+ return { ...state, messages: [...state.messages, ...action.payload] };
125
+ case 'SET_INPUT':
126
+ return { ...state, input: action.payload };
127
+ case 'SET_LOADING':
128
+ return { ...state, isLoading: action.payload };
129
+ case 'SET_ERROR':
130
+ return { ...state, error: action.payload };
131
+ case 'SET_CONFIG':
132
+ return { ...state, config: action.payload };
133
+ case 'UPDATE_CONFIG_FIELD':
134
+ return {
135
+ ...state,
136
+ config: { ...state.config, [action.payload.field]: action.payload.value }
137
+ };
138
+ case 'SET_MCP_CONFIG':
139
+ return { ...state, mcpConfig: { ...state.mcpConfig, ...action.payload } };
140
+ case 'SET_EDITING_FILESYSTEM_PATH':
141
+ return { ...state, editingFilesystemPath: action.payload };
142
+ case 'SET_CURRENT_FIELD':
143
+ return { ...state, currentField: action.payload };
144
+ case 'SET_LOGS':
145
+ return { ...state, logs: action.payload };
146
+ default:
147
+ return state;
148
+ }
149
+ };
150
+ export const AppProvider = ({ children, accountId, privateKey, network = 'testnet', openAIApiKey, }) => {
151
+ const agentRef = useRef(null);
152
+ const initializingRef = useRef(false);
153
+ const autoInitialized = useRef(false);
154
+ const getInitialState = () => {
155
+ const envConfig = loadConfigFromEnv();
156
+ const loadedServers = loadMCPConfig();
157
+ const filesystemServer = loadedServers.find(s => s.name === 'filesystem');
158
+ const customServers = loadedServers.filter(s => s.name !== 'filesystem');
159
+ return {
160
+ screen: 'welcome',
161
+ agent: null,
162
+ messages: [],
163
+ input: '',
164
+ isLoading: false,
165
+ error: null,
166
+ config: {
167
+ accountId: accountId || envConfig.accountId,
168
+ privateKey: privateKey || envConfig.privateKey,
169
+ network: network || envConfig.network,
170
+ openAIApiKey: openAIApiKey || envConfig.openAIApiKey,
171
+ mcpServers: envConfig.mcpServers || [],
172
+ },
173
+ mcpConfig: {
174
+ enableFilesystem: !!filesystemServer,
175
+ filesystemPath: filesystemServer ? filesystemServer.args[2] || process.cwd() : process.cwd(),
176
+ customServers,
177
+ addingCustom: false,
178
+ newServerName: '',
179
+ newServerCommand: '',
180
+ newServerArgs: '',
181
+ newServerEnv: '',
182
+ currentField: 0,
183
+ },
184
+ editingFilesystemPath: false,
185
+ currentField: 0,
186
+ logs: [],
187
+ };
188
+ };
189
+ const [state, dispatch] = useReducer(appReducer, getInitialState());
190
+ const initializeAgent = useCallback(async () => {
191
+ if (agentRef.current) {
192
+ dispatch({ type: 'SET_AGENT', payload: agentRef.current });
193
+ dispatch({ type: 'SET_SCREEN', payload: 'chat' });
194
+ return;
195
+ }
196
+ if (initializingRef.current) {
197
+ return;
198
+ }
199
+ initializingRef.current = true;
200
+ dispatch({ type: 'SET_LOADING', payload: true });
201
+ dispatch({ type: 'SET_ERROR', payload: null });
202
+ try {
203
+ saveConfig(state.config);
204
+ const mcpServers = [];
205
+ if (state.mcpConfig.enableFilesystem && state.mcpConfig.filesystemPath) {
206
+ mcpServers.push(MCPServers.filesystem(state.mcpConfig.filesystemPath));
207
+ }
208
+ mcpServers.push(...state.mcpConfig.customServers);
209
+ const agentConfig = {
210
+ accountId: state.config.accountId,
211
+ privateKey: state.config.privateKey,
212
+ network: state.config.network,
213
+ openAIApiKey: state.config.openAIApiKey,
214
+ openAIModelName: 'gpt-4o-mini',
215
+ verbose: false,
216
+ disableLogging: true,
217
+ ...(mcpServers.length > 0 && { mcpServers }),
218
+ };
219
+ const conversationalAgent = new ConversationalAgent(agentConfig);
220
+ await conversationalAgent.initialize();
221
+ agentRef.current = conversationalAgent;
222
+ dispatch({ type: 'SET_AGENT', payload: conversationalAgent });
223
+ dispatch({ type: 'SET_SCREEN', payload: 'chat' });
224
+ const welcomeMessages = [
225
+ {
226
+ role: 'system',
227
+ content: `Connected to Hedera ${state.config.network}`,
228
+ timestamp: new Date(),
229
+ },
230
+ ];
231
+ if (mcpServers.length > 0) {
232
+ welcomeMessages.push({
233
+ role: 'system',
234
+ content: `MCP servers enabled: ${mcpServers.map(s => s.name).join(', ')}`,
235
+ timestamp: new Date(),
236
+ });
237
+ }
238
+ welcomeMessages.push({
239
+ role: 'assistant',
240
+ content: mcpServers.length > 0
241
+ ? "Hello! I'm your Hashgraph Consensus Standards Conversational Agent with extended MCP capabilities. I can help you manage HCS-10 agent registrations, HCS-11 profiles, send messages through HCS standards, interact with the Hedera network, and use external tools for file operations and more. How can I assist you today?"
242
+ : "Hello! I'm your Hashgraph Consensus Standards Conversational Agent. I can help you manage HCS-10 agent registrations, HCS-11 profiles, send messages through HCS standards, and interact with the Hedera network. How can I assist you today?",
243
+ timestamp: new Date(),
244
+ });
245
+ dispatch({ type: 'SET_MESSAGES', payload: welcomeMessages });
246
+ }
247
+ catch (err) {
248
+ dispatch({
249
+ type: 'SET_ERROR',
250
+ payload: err instanceof Error ? err.message : 'Failed to initialize agent',
251
+ });
252
+ dispatch({ type: 'SET_SCREEN', payload: 'setup' });
253
+ }
254
+ finally {
255
+ dispatch({ type: 'SET_LOADING', payload: false });
256
+ initializingRef.current = false;
257
+ }
258
+ }, [state.config, state.mcpConfig]);
259
+ const sendMessage = useCallback(async (message) => {
260
+ const currentAgent = agentRef.current || state.agent;
261
+ if (!currentAgent || !message.trim())
262
+ return;
263
+ const userMessage = {
264
+ role: 'user',
265
+ content: message,
266
+ timestamp: new Date(),
267
+ };
268
+ dispatch({ type: 'ADD_MESSAGES', payload: [userMessage] });
269
+ dispatch({ type: 'SET_INPUT', payload: '' });
270
+ dispatch({ type: 'SET_LOADING', payload: true });
271
+ try {
272
+ const chatHistory = state.messages
273
+ .filter(m => m.role !== 'system')
274
+ .map(m => ({
275
+ type: m.role === 'user' ? 'human' : 'ai',
276
+ content: m.content,
277
+ }));
278
+ const response = await currentAgent.processMessage(message, chatHistory);
279
+ const assistantMessage = {
280
+ role: 'assistant',
281
+ content: response.message || response.output || response.error || 'No response received',
282
+ timestamp: new Date(),
283
+ };
284
+ const newMessages = [assistantMessage];
285
+ if (response.transactionId) {
286
+ newMessages.push({
287
+ role: 'system',
288
+ content: `Transaction ID: ${response.transactionId}`,
289
+ timestamp: new Date(),
290
+ });
291
+ }
292
+ if (response.scheduleId) {
293
+ newMessages.push({
294
+ role: 'system',
295
+ content: `Schedule ID: ${response.scheduleId}`,
296
+ timestamp: new Date(),
297
+ });
298
+ }
299
+ if (response.notes && response.notes.length > 0) {
300
+ response.notes.forEach((note) => {
301
+ newMessages.push({
302
+ role: 'system',
303
+ content: note,
304
+ timestamp: new Date(),
305
+ });
306
+ });
307
+ }
308
+ dispatch({ type: 'ADD_MESSAGES', payload: newMessages });
309
+ }
310
+ catch (err) {
311
+ dispatch({
312
+ type: 'ADD_MESSAGES',
313
+ payload: [{
314
+ role: 'system',
315
+ content: `Error: ${err instanceof Error ? err.message : 'Unknown error'}`,
316
+ timestamp: new Date(),
317
+ }],
318
+ });
319
+ }
320
+ finally {
321
+ dispatch({ type: 'SET_LOADING', payload: false });
322
+ }
323
+ }, [state.agent, state.messages]);
324
+ const actions = {
325
+ setScreen: useCallback((screen) => dispatch({ type: 'SET_SCREEN', payload: screen }), []),
326
+ setAgent: useCallback((agent) => dispatch({ type: 'SET_AGENT', payload: agent }), []),
327
+ setMessages: useCallback((messages) => dispatch({ type: 'SET_MESSAGES', payload: messages }), []),
328
+ addMessages: useCallback((messages) => dispatch({ type: 'ADD_MESSAGES', payload: messages }), []),
329
+ setInput: useCallback((input) => dispatch({ type: 'SET_INPUT', payload: input }), []),
330
+ setLoading: useCallback((loading) => dispatch({ type: 'SET_LOADING', payload: loading }), []),
331
+ setError: useCallback((error) => dispatch({ type: 'SET_ERROR', payload: error }), []),
332
+ setConfig: useCallback((config) => dispatch({ type: 'SET_CONFIG', payload: config }), []),
333
+ updateConfigField: useCallback((field, value) => dispatch({ type: 'UPDATE_CONFIG_FIELD', payload: { field, value } }), []),
334
+ setMcpConfig: useCallback((config) => dispatch({ type: 'SET_MCP_CONFIG', payload: config }), []),
335
+ setEditingFilesystemPath: useCallback((editing) => dispatch({ type: 'SET_EDITING_FILESYSTEM_PATH', payload: editing }), []),
336
+ setCurrentField: useCallback((field) => dispatch({ type: 'SET_CURRENT_FIELD', payload: field }), []),
337
+ setLogs: useCallback((logs) => dispatch({ type: 'SET_LOGS', payload: logs }), []),
338
+ initializeAgent,
339
+ sendMessage,
340
+ };
341
+ useEffect(() => {
342
+ const hasRequiredConfig = state.config.accountId &&
343
+ state.config.privateKey &&
344
+ state.config.openAIApiKey;
345
+ if (hasRequiredConfig && !autoInitialized.current && !agentRef.current) {
346
+ autoInitialized.current = true;
347
+ initializeAgent();
348
+ }
349
+ }, [state.config.accountId, state.config.privateKey, state.config.openAIApiKey, initializeAgent]);
350
+ const contextValue = {
351
+ state,
352
+ actions,
353
+ };
354
+ return React.createElement(AppContext.Provider, { value: contextValue }, children);
355
+ };
356
+ export const useAppContext = () => {
357
+ const context = useContext(AppContext);
358
+ if (!context) {
359
+ throw new Error('useAppContext must be used within an AppProvider');
360
+ }
361
+ return context;
362
+ };
363
+ export { saveMCPConfig, getMCPConfigPath };
@@ -0,0 +1,19 @@
1
+ import { ConfigManager } from '../managers/ConfigManager';
2
+ import { AgentManager } from '../managers/AgentManager';
3
+ import { type Config } from '../types';
4
+ import { type MCPServerConfig } from '@hashgraphonline/conversational-agent';
5
+ interface InitializeAgentProps {
6
+ configManager: ConfigManager;
7
+ agentManager: AgentManager;
8
+ actions: {
9
+ setScreen: (screen: any) => void;
10
+ setMessages: (messages: any[]) => void;
11
+ setError: (error: string | null) => void;
12
+ };
13
+ }
14
+ export declare const useInitializeAgent: ({ configManager, agentManager, actions, }: InitializeAgentProps) => (currentConfig: Config, mcpConfig: {
15
+ enableFilesystem: boolean;
16
+ filesystemPath: string;
17
+ customServers: MCPServerConfig[];
18
+ }) => Promise<void>;
19
+ export {};
@@ -0,0 +1,28 @@
1
+ import { useRef, useCallback } from 'react';
2
+ export const useInitializeAgent = ({ configManager, agentManager, actions, }) => {
3
+ const initializingRef = useRef(false);
4
+ const initializeAgent = useCallback(async (currentConfig, mcpConfig) => {
5
+ if (agentManager.isInitialized() ||
6
+ agentManager.isInitializing() ||
7
+ initializingRef.current) {
8
+ return;
9
+ }
10
+ initializingRef.current = true;
11
+ actions.setScreen('loading');
12
+ try {
13
+ await configManager.saveConfig(currentConfig);
14
+ const { welcomeMessages } = await agentManager.initialize({ ...currentConfig, mcpServers: configManager.getMCPServers() }, mcpConfig);
15
+ actions.setMessages(welcomeMessages);
16
+ await new Promise(resolve => setTimeout(resolve, 100));
17
+ actions.setScreen('chat');
18
+ }
19
+ catch (err) {
20
+ actions.setError(err instanceof Error ? err.message : 'Failed to initialize agent');
21
+ actions.setScreen('setup');
22
+ }
23
+ finally {
24
+ initializingRef.current = false;
25
+ }
26
+ }, [configManager, agentManager, actions]);
27
+ return initializeAgent;
28
+ };
@@ -0,0 +1,38 @@
1
+ import { type Screen, type Message } from '../types';
2
+ import { type MCPServerConfig } from '@hashgraphonline/conversational-agent';
3
+ export interface AppState {
4
+ screen: Screen;
5
+ messages: Message[];
6
+ input: string;
7
+ isLoading: boolean;
8
+ error: string | null;
9
+ mcpConfig: {
10
+ enableFilesystem: boolean;
11
+ filesystemPath: string;
12
+ customServers: MCPServerConfig[];
13
+ addingCustom: boolean;
14
+ newServerName: string;
15
+ newServerCommand: string;
16
+ newServerArgs: string;
17
+ newServerEnv: string;
18
+ currentField: number;
19
+ };
20
+ editingFilesystemPath: boolean;
21
+ currentField: number;
22
+ logs: string[];
23
+ }
24
+ export declare const useStableState: (initialMcpServers: MCPServerConfig[]) => {
25
+ state: AppState;
26
+ actions: {
27
+ setScreen: (screen: Screen) => void;
28
+ setMessages: (messages: Message[]) => void;
29
+ addMessages: (messages: Message[]) => void;
30
+ setInput: (input: string) => void;
31
+ setLoading: (loading: boolean) => void;
32
+ setError: (error: string | null) => void;
33
+ setMcpConfig: (config: Partial<AppState["mcpConfig"]>) => void;
34
+ setEditingFilesystemPath: (editing: boolean) => void;
35
+ setCurrentField: (field: number) => void;
36
+ setLogs: (logs: string[]) => void;
37
+ };
38
+ };
@@ -0,0 +1,68 @@
1
+ import { useReducer, useCallback, useMemo } from 'react';
2
+ const appReducer = (state, action) => {
3
+ switch (action.type) {
4
+ case 'SET_SCREEN':
5
+ return { ...state, screen: action.payload };
6
+ case 'SET_MESSAGES':
7
+ return { ...state, messages: action.payload };
8
+ case 'ADD_MESSAGES':
9
+ return { ...state, messages: [...state.messages, ...action.payload] };
10
+ case 'SET_INPUT':
11
+ return { ...state, input: action.payload };
12
+ case 'SET_LOADING':
13
+ return { ...state, isLoading: action.payload };
14
+ case 'SET_ERROR':
15
+ return { ...state, error: action.payload };
16
+ case 'SET_MCP_CONFIG':
17
+ return { ...state, mcpConfig: { ...state.mcpConfig, ...action.payload } };
18
+ case 'SET_EDITING_FILESYSTEM_PATH':
19
+ return { ...state, editingFilesystemPath: action.payload };
20
+ case 'SET_CURRENT_FIELD':
21
+ return { ...state, currentField: action.payload };
22
+ case 'SET_LOGS':
23
+ return { ...state, logs: action.payload };
24
+ default:
25
+ return state;
26
+ }
27
+ };
28
+ export const useStableState = (initialMcpServers) => {
29
+ const getInitialState = useCallback(() => {
30
+ const filesystemServer = initialMcpServers.find(s => s.name === 'filesystem');
31
+ const customServers = initialMcpServers.filter(s => s.name !== 'filesystem');
32
+ return {
33
+ screen: 'welcome',
34
+ messages: [],
35
+ input: '',
36
+ isLoading: false,
37
+ error: null,
38
+ mcpConfig: {
39
+ enableFilesystem: !!filesystemServer,
40
+ filesystemPath: filesystemServer ? filesystemServer.args[2] || process.cwd() : process.cwd(),
41
+ customServers,
42
+ addingCustom: false,
43
+ newServerName: '',
44
+ newServerCommand: '',
45
+ newServerArgs: '',
46
+ newServerEnv: '',
47
+ currentField: 0,
48
+ },
49
+ editingFilesystemPath: false,
50
+ currentField: 0,
51
+ logs: [],
52
+ };
53
+ }, [initialMcpServers]);
54
+ const [state, dispatch] = useReducer(appReducer, null, getInitialState);
55
+ const actions = useMemo(() => ({
56
+ setScreen: (screen) => dispatch({ type: 'SET_SCREEN', payload: screen }),
57
+ setMessages: (messages) => dispatch({ type: 'SET_MESSAGES', payload: messages }),
58
+ addMessages: (messages) => dispatch({ type: 'ADD_MESSAGES', payload: messages }),
59
+ setInput: (input) => dispatch({ type: 'SET_INPUT', payload: input }),
60
+ setLoading: (loading) => dispatch({ type: 'SET_LOADING', payload: loading }),
61
+ setError: (error) => dispatch({ type: 'SET_ERROR', payload: error }),
62
+ setMcpConfig: (config) => dispatch({ type: 'SET_MCP_CONFIG', payload: config }),
63
+ setEditingFilesystemPath: (editing) => dispatch({ type: 'SET_EDITING_FILESYSTEM_PATH', payload: editing }),
64
+ setCurrentField: (field) => dispatch({ type: 'SET_CURRENT_FIELD', payload: field }),
65
+ setLogs: (logs) => dispatch({ type: 'SET_LOGS', payload: logs }),
66
+ }), [dispatch]);
67
+ return { state, actions };
68
+ };
@@ -0,0 +1,57 @@
1
+ import { ConversationalAgent, type MCPServerConfig } from '@hashgraphonline/conversational-agent';
2
+ import { type Config, type Message } from '../types';
3
+ export declare class AgentManager {
4
+ private static instance;
5
+ private agent;
6
+ private initializing;
7
+ private initialized;
8
+ private constructor();
9
+ static getInstance(): AgentManager;
10
+ /**
11
+ * Initialize the conversational agent
12
+ */
13
+ initialize(config: Config & {
14
+ mcpServers: MCPServerConfig[];
15
+ }, mcpConfig: {
16
+ enableFilesystem: boolean;
17
+ filesystemPath: string;
18
+ customServers: MCPServerConfig[];
19
+ }): Promise<{
20
+ agent: ConversationalAgent;
21
+ welcomeMessages: Message[];
22
+ }>;
23
+ /**
24
+ * Get welcome messages
25
+ */
26
+ private getWelcomeMessages;
27
+ /**
28
+ * Send message to agent
29
+ */
30
+ sendMessage(message: string, chatHistory: Array<{
31
+ type: 'human' | 'ai';
32
+ content: string;
33
+ }>): Promise<{
34
+ message?: string;
35
+ output?: string;
36
+ error?: string;
37
+ transactionId?: string;
38
+ scheduleId?: string;
39
+ notes?: string[];
40
+ }>;
41
+ /**
42
+ * Get current agent
43
+ */
44
+ getAgent(): ConversationalAgent | null;
45
+ /**
46
+ * Check if agent is initialized
47
+ */
48
+ isInitialized(): boolean;
49
+ /**
50
+ * Check if agent is initializing
51
+ */
52
+ isInitializing(): boolean;
53
+ /**
54
+ * Reset agent (for testing)
55
+ */
56
+ reset(): void;
57
+ }