@emblemvault/agentwallet 1.1.0 → 1.2.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/README.md +45 -18
- package/{hustle-chat.js → emblemai.js} +371 -418
- package/package.json +7 -18
- package/auth.js +0 -38
- package/conversation.js +0 -83
- package/enhanced-hustle.js +0 -102
- package/reset-conversation.js +0 -44
- package/resume-conversation.js +0 -124
|
@@ -1,51 +1,82 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* EmblemAI - Unified CLI for Agent Hustle
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Agent Mode (for AI agents):
|
|
7
|
+
* emblemai --agent -p "password" -m "What are my balances?"
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Interactive Mode (for humans):
|
|
10
|
+
* emblemai -p "password"
|
|
11
|
+
* emblemai # Will prompt for password
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* AUTH_API_URL - Auth API URL (optional, uses SDK default)
|
|
17
|
-
* HUSTLE_API_URL - Hustle API URL (optional, uses SDK default)
|
|
18
|
-
* DEBUG - Enable debug logging (set to 'true')
|
|
13
|
+
* Reset conversation:
|
|
14
|
+
* emblemai --reset
|
|
15
|
+
* (or /reset in interactive mode)
|
|
19
16
|
*/
|
|
20
17
|
|
|
21
18
|
async function main() {
|
|
22
19
|
try {
|
|
23
|
-
// Import dependencies
|
|
24
20
|
const { HustleIncognitoClient } = await import('hustle-incognito');
|
|
25
21
|
const { EmblemAuthSDK } = await import('@emblemvault/auth-sdk');
|
|
26
|
-
const dotenv = await import('dotenv');
|
|
27
22
|
const readline = await import('readline');
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
const fs = await import('fs');
|
|
24
|
+
const path = await import('path');
|
|
25
|
+
const os = await import('os');
|
|
31
26
|
|
|
32
27
|
// Parse command line arguments
|
|
33
28
|
const args = process.argv.slice(2);
|
|
34
|
-
const getArg = (
|
|
35
|
-
const
|
|
36
|
-
|
|
29
|
+
const getArg = (flags) => {
|
|
30
|
+
for (const flag of flags) {
|
|
31
|
+
const index = args.indexOf(flag);
|
|
32
|
+
if (index !== -1 && args[index + 1]) return args[index + 1];
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
37
35
|
};
|
|
36
|
+
const hasFlag = (flags) => flags.some(f => args.includes(f));
|
|
37
|
+
|
|
38
|
+
const isAgentMode = hasFlag(['--agent', '-a']);
|
|
39
|
+
const isReset = hasFlag(['--reset']);
|
|
40
|
+
const initialDebug = hasFlag(['--debug']);
|
|
41
|
+
const initialStream = hasFlag(['--stream']);
|
|
42
|
+
const passwordArg = getArg(['--password', '-p']);
|
|
43
|
+
const messageArg = getArg(['--message', '-m']);
|
|
44
|
+
|
|
45
|
+
// Conversation history file
|
|
46
|
+
const historyFile = path.join(os.homedir(), '.emblemai-history.json');
|
|
47
|
+
|
|
48
|
+
// Load conversation history
|
|
49
|
+
function loadHistory() {
|
|
50
|
+
try {
|
|
51
|
+
if (fs.existsSync(historyFile)) {
|
|
52
|
+
const data = fs.readFileSync(historyFile, 'utf8');
|
|
53
|
+
return JSON.parse(data);
|
|
54
|
+
}
|
|
55
|
+
} catch (e) {
|
|
56
|
+
// Ignore errors, start fresh
|
|
57
|
+
}
|
|
58
|
+
return { messages: [], created: new Date().toISOString() };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Save conversation history
|
|
62
|
+
function saveHistory(history) {
|
|
63
|
+
history.lastUpdated = new Date().toISOString();
|
|
64
|
+
fs.writeFileSync(historyFile, JSON.stringify(history, null, 2));
|
|
65
|
+
}
|
|
38
66
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
67
|
+
// Reset conversation history
|
|
68
|
+
function resetHistory() {
|
|
69
|
+
if (fs.existsSync(historyFile)) {
|
|
70
|
+
fs.unlinkSync(historyFile);
|
|
71
|
+
}
|
|
72
|
+
console.log('Conversation history cleared.');
|
|
73
|
+
}
|
|
42
74
|
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const ENV_DEBUG = process.env.DEBUG === 'true';
|
|
75
|
+
// Handle --reset flag
|
|
76
|
+
if (isReset) {
|
|
77
|
+
resetHistory();
|
|
78
|
+
process.exit(0);
|
|
79
|
+
}
|
|
49
80
|
|
|
50
81
|
// Create readline interface
|
|
51
82
|
const rl = readline.createInterface({
|
|
@@ -53,22 +84,18 @@ async function main() {
|
|
|
53
84
|
output: process.stdout
|
|
54
85
|
});
|
|
55
86
|
|
|
56
|
-
// Helper to prompt for input
|
|
57
87
|
const prompt = (question) => new Promise((resolve) => {
|
|
58
88
|
rl.question(question, resolve);
|
|
59
89
|
});
|
|
60
90
|
|
|
61
|
-
//
|
|
91
|
+
// Hidden password input
|
|
62
92
|
const promptPassword = async (question) => {
|
|
63
93
|
if (process.stdin.isTTY) {
|
|
64
94
|
process.stdout.write(question);
|
|
65
|
-
|
|
66
95
|
return new Promise((resolve) => {
|
|
67
96
|
let password = '';
|
|
68
|
-
|
|
69
97
|
const onData = (char) => {
|
|
70
98
|
char = char.toString();
|
|
71
|
-
|
|
72
99
|
switch (char) {
|
|
73
100
|
case '\n':
|
|
74
101
|
case '\r':
|
|
@@ -92,7 +119,6 @@ async function main() {
|
|
|
92
119
|
process.stdout.write('*');
|
|
93
120
|
}
|
|
94
121
|
};
|
|
95
|
-
|
|
96
122
|
process.stdin.setRawMode(true);
|
|
97
123
|
process.stdin.resume();
|
|
98
124
|
process.stdin.on('data', onData);
|
|
@@ -102,105 +128,122 @@ async function main() {
|
|
|
102
128
|
}
|
|
103
129
|
};
|
|
104
130
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
console.log('========================================');
|
|
108
|
-
console.log('');
|
|
109
|
-
console.log('This CLI uses headless password authentication.');
|
|
110
|
-
console.log('No API key required - authentication is via password.');
|
|
111
|
-
console.log('');
|
|
131
|
+
// Get password from args, env, file, or prompt
|
|
132
|
+
let password = passwordArg || process.env.EMBLEM_PASSWORD || process.env.AGENT_PASSWORD;
|
|
112
133
|
|
|
113
|
-
//
|
|
114
|
-
|
|
134
|
+
// Try credential file
|
|
135
|
+
if (!password) {
|
|
136
|
+
const credFile = path.join(os.homedir(), '.emblem-vault');
|
|
137
|
+
if (fs.existsSync(credFile)) {
|
|
138
|
+
password = fs.readFileSync(credFile, 'utf8').trim();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
115
141
|
|
|
142
|
+
// Prompt if still no password
|
|
116
143
|
if (!password) {
|
|
117
|
-
|
|
144
|
+
if (isAgentMode) {
|
|
145
|
+
console.error('Error: Password required in agent mode. Use -p or set EMBLEM_PASSWORD');
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
118
148
|
console.log('');
|
|
119
|
-
password = await promptPassword('Enter your password (min 16 chars): ');
|
|
149
|
+
password = await promptPassword('Enter your EmblemVault password (min 16 chars): ');
|
|
120
150
|
}
|
|
121
151
|
|
|
122
|
-
// Validate password
|
|
123
152
|
if (!password || password.length < 16) {
|
|
124
|
-
console.error('
|
|
125
|
-
console.error('Use a long, random string like an API key for security.');
|
|
153
|
+
console.error('Error: Password must be at least 16 characters.');
|
|
126
154
|
process.exit(1);
|
|
127
155
|
}
|
|
128
156
|
|
|
129
|
-
|
|
130
|
-
|
|
157
|
+
// Authenticate
|
|
158
|
+
if (!isAgentMode) {
|
|
159
|
+
console.log('');
|
|
160
|
+
console.log('Authenticating with Agent Hustle...');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const authSdk = new EmblemAuthSDK({
|
|
164
|
+
appId: 'emblem-agent-wallet',
|
|
165
|
+
persistSession: false,
|
|
166
|
+
});
|
|
131
167
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
168
|
+
const session = await authSdk.authenticatePassword({ password });
|
|
169
|
+
if (!session) {
|
|
170
|
+
throw new Error('Authentication failed');
|
|
171
|
+
}
|
|
135
172
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
173
|
+
// Settings (runtime state)
|
|
174
|
+
const settings = {
|
|
175
|
+
debug: initialDebug,
|
|
176
|
+
stream: !initialStream ? true : initialStream, // Default ON
|
|
177
|
+
retainHistory: true,
|
|
178
|
+
selectedTools: [],
|
|
179
|
+
model: null,
|
|
180
|
+
};
|
|
141
181
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
182
|
+
const client = new HustleIncognitoClient({
|
|
183
|
+
sdk: authSdk,
|
|
184
|
+
debug: settings.debug,
|
|
185
|
+
});
|
|
145
186
|
|
|
146
|
-
|
|
187
|
+
// Intent context for auto-tools mode
|
|
188
|
+
let lastIntentContext = null;
|
|
147
189
|
|
|
148
|
-
|
|
149
|
-
|
|
190
|
+
// Load existing history (resume by default)
|
|
191
|
+
let history = loadHistory();
|
|
150
192
|
|
|
151
|
-
|
|
152
|
-
|
|
193
|
+
// ==================== AGENT MODE ====================
|
|
194
|
+
if (isAgentMode) {
|
|
195
|
+
if (!messageArg) {
|
|
196
|
+
console.error('Error: Message required in agent mode. Use -m "your message"');
|
|
197
|
+
process.exit(1);
|
|
153
198
|
}
|
|
154
199
|
|
|
155
|
-
|
|
156
|
-
const clientConfig = {
|
|
157
|
-
sdk: authSdk,
|
|
158
|
-
debug: initialDebugMode || ENV_DEBUG,
|
|
159
|
-
};
|
|
200
|
+
console.log('Agent Hustle is thinking.');
|
|
160
201
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
202
|
+
// Add user message to history
|
|
203
|
+
history.messages.push({ role: 'user', content: messageArg });
|
|
164
204
|
|
|
165
|
-
|
|
205
|
+
// Progress indicator - output a dot every 5 seconds to show it's not hung
|
|
206
|
+
const progressInterval = setInterval(() => {
|
|
207
|
+
process.stdout.write('.');
|
|
208
|
+
}, 5000);
|
|
166
209
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (error.message.includes('@emblemvault/auth-sdk')) {
|
|
170
|
-
console.error('\nTo install the auth SDK:');
|
|
171
|
-
console.error(' npm install @emblemvault/auth-sdk');
|
|
172
|
-
}
|
|
173
|
-
process.exit(1);
|
|
174
|
-
}
|
|
210
|
+
try {
|
|
211
|
+
const response = await client.chat(history.messages);
|
|
175
212
|
|
|
176
|
-
|
|
177
|
-
|
|
213
|
+
// Stop progress indicator
|
|
214
|
+
clearInterval(progressInterval);
|
|
178
215
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
216
|
+
// Add assistant response to history
|
|
217
|
+
history.messages.push({ role: 'assistant', content: response.content });
|
|
218
|
+
saveHistory(history);
|
|
219
|
+
|
|
220
|
+
// Output response (for agent to capture)
|
|
221
|
+
console.log(response.content);
|
|
222
|
+
} catch (error) {
|
|
223
|
+
clearInterval(progressInterval);
|
|
224
|
+
console.error('Error:', error.message);
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
187
227
|
|
|
188
|
-
|
|
189
|
-
|
|
228
|
+
rl.close();
|
|
229
|
+
process.exit(0);
|
|
230
|
+
}
|
|
190
231
|
|
|
191
|
-
//
|
|
192
|
-
|
|
232
|
+
// ==================== INTERACTIVE MODE ====================
|
|
233
|
+
console.log('');
|
|
234
|
+
console.log('========================================');
|
|
235
|
+
console.log(' Agent Hustle CLI');
|
|
236
|
+
console.log('========================================');
|
|
237
|
+
console.log('');
|
|
193
238
|
|
|
194
|
-
// Spinner
|
|
239
|
+
// Spinner
|
|
195
240
|
const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
196
241
|
let spinnerInterval = null;
|
|
197
242
|
let spinnerIndex = 0;
|
|
198
|
-
const hideCursor = '\x1B[?25l';
|
|
199
|
-
const showCursor = '\x1B[?25h';
|
|
200
243
|
|
|
201
244
|
function startSpinner() {
|
|
202
245
|
spinnerIndex = 0;
|
|
203
|
-
process.stdout.write(
|
|
246
|
+
process.stdout.write('\x1B[?25l' + spinnerFrames[0]);
|
|
204
247
|
spinnerInterval = setInterval(() => {
|
|
205
248
|
process.stdout.write('\b' + spinnerFrames[spinnerIndex]);
|
|
206
249
|
spinnerIndex = (spinnerIndex + 1) % spinnerFrames.length;
|
|
@@ -211,133 +254,44 @@ async function main() {
|
|
|
211
254
|
if (spinnerInterval) {
|
|
212
255
|
clearInterval(spinnerInterval);
|
|
213
256
|
spinnerInterval = null;
|
|
214
|
-
process.stdout.write('\b \b'
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// Stream response
|
|
219
|
-
async function streamResponse(msgs) {
|
|
220
|
-
let fullText = '';
|
|
221
|
-
let toolCalls = [];
|
|
222
|
-
let firstChunkReceived = false;
|
|
223
|
-
|
|
224
|
-
process.stdout.write('\nAgent: ');
|
|
225
|
-
startSpinner();
|
|
226
|
-
|
|
227
|
-
try {
|
|
228
|
-
const streamOptions = {
|
|
229
|
-
messages: msgs,
|
|
230
|
-
processChunks: true
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
if (settings.model) {
|
|
234
|
-
streamOptions.model = settings.model;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (settings.selectedTools.length > 0) {
|
|
238
|
-
streamOptions.selectedToolCategories = settings.selectedTools;
|
|
239
|
-
} else if (lastIntentContext) {
|
|
240
|
-
streamOptions.intentContext = lastIntentContext;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const stream = client.chatStream(streamOptions);
|
|
244
|
-
|
|
245
|
-
for await (const chunk of stream) {
|
|
246
|
-
if ('type' in chunk) {
|
|
247
|
-
switch (chunk.type) {
|
|
248
|
-
case 'text':
|
|
249
|
-
if (!firstChunkReceived) {
|
|
250
|
-
stopSpinner();
|
|
251
|
-
firstChunkReceived = true;
|
|
252
|
-
}
|
|
253
|
-
process.stdout.write(chunk.value);
|
|
254
|
-
fullText += chunk.value;
|
|
255
|
-
break;
|
|
256
|
-
|
|
257
|
-
case 'intent_context':
|
|
258
|
-
if (chunk.value?.intentContext) {
|
|
259
|
-
lastIntentContext = chunk.value.intentContext;
|
|
260
|
-
if (settings.debug) {
|
|
261
|
-
console.log('[DEBUG] Captured intent context:',
|
|
262
|
-
`activeIntent="${lastIntentContext.activeIntent || 'general'}", ` +
|
|
263
|
-
`categories=[${lastIntentContext.categories?.join(', ') || 'none'}]`);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
break;
|
|
267
|
-
|
|
268
|
-
case 'tool_call':
|
|
269
|
-
if (!firstChunkReceived) {
|
|
270
|
-
stopSpinner();
|
|
271
|
-
firstChunkReceived = true;
|
|
272
|
-
}
|
|
273
|
-
toolCalls.push(chunk.value);
|
|
274
|
-
break;
|
|
275
|
-
|
|
276
|
-
case 'finish':
|
|
277
|
-
stopSpinner();
|
|
278
|
-
process.stdout.write('\n');
|
|
279
|
-
break;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
} catch (error) {
|
|
284
|
-
stopSpinner();
|
|
285
|
-
console.error(`\nError during streaming: ${error.message}`);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if (toolCalls.length > 0) {
|
|
289
|
-
console.log('\nTools used:');
|
|
290
|
-
toolCalls.forEach((tool, i) => {
|
|
291
|
-
console.log(`${i+1}. ${tool.toolName || 'Unknown tool'} (ID: ${tool.toolCallId || 'unknown'})`);
|
|
292
|
-
if (tool.args) {
|
|
293
|
-
console.log(` Args: ${JSON.stringify(tool.args)}`);
|
|
294
|
-
}
|
|
295
|
-
});
|
|
257
|
+
process.stdout.write('\b \b\x1B[?25h');
|
|
296
258
|
}
|
|
297
|
-
|
|
298
|
-
return fullText;
|
|
299
259
|
}
|
|
300
260
|
|
|
301
|
-
//
|
|
261
|
+
// ==================== HELP ====================
|
|
302
262
|
function showHelp() {
|
|
303
|
-
console.log('\
|
|
304
|
-
console.log(' /help
|
|
305
|
-
console.log(' /settings
|
|
306
|
-
console.log(' /auth
|
|
263
|
+
console.log('\nCommands:');
|
|
264
|
+
console.log(' /help - Show this help');
|
|
265
|
+
console.log(' /settings - Show current settings');
|
|
266
|
+
console.log(' /auth - Open auth menu (API key, addresses, etc.)');
|
|
307
267
|
console.log(' /stream on|off - Toggle streaming mode');
|
|
308
268
|
console.log(' /debug on|off - Toggle debug mode');
|
|
309
|
-
console.log(' /history on|off - Toggle
|
|
310
|
-
console.log(' /
|
|
311
|
-
console.log(' /models
|
|
312
|
-
console.log(' /model <id>
|
|
313
|
-
console.log(' /
|
|
314
|
-
console.log(' /tools
|
|
315
|
-
console.log(' /tools
|
|
316
|
-
console.log(' /
|
|
317
|
-
console.log(' /tools clear - Enable auto-tools mode');
|
|
318
|
-
console.log(' /exit or /quit - Exit the application');
|
|
269
|
+
console.log(' /history on|off - Toggle history retention');
|
|
270
|
+
console.log(' /reset - Clear conversation history');
|
|
271
|
+
console.log(' /models - List available models');
|
|
272
|
+
console.log(' /model <id> - Set model (or "clear" to reset)');
|
|
273
|
+
console.log(' /tools - List tool categories');
|
|
274
|
+
console.log(' /tools add|remove <id> - Manage tools');
|
|
275
|
+
console.log(' /tools clear - Enable auto-tools mode');
|
|
276
|
+
console.log(' /exit - Exit the CLI');
|
|
319
277
|
}
|
|
320
278
|
|
|
321
|
-
//
|
|
279
|
+
// ==================== SETTINGS ====================
|
|
322
280
|
function showSettings() {
|
|
323
|
-
const
|
|
281
|
+
const sess = authSdk.getSession();
|
|
324
282
|
console.log('\nCurrent settings:');
|
|
325
|
-
console.log(` App ID:
|
|
326
|
-
console.log(` Vault ID: ${
|
|
283
|
+
console.log(` App ID: emblem-agent-wallet`);
|
|
284
|
+
console.log(` Vault ID: ${sess?.user?.vaultId || 'N/A'}`);
|
|
327
285
|
console.log(` Auth Mode: Password (headless)`);
|
|
328
286
|
console.log(` Model: ${settings.model || 'API default'}`);
|
|
329
287
|
console.log(` Streaming: ${settings.stream ? 'ON' : 'OFF'}`);
|
|
330
288
|
console.log(` Debug: ${settings.debug ? 'ON' : 'OFF'}`);
|
|
331
289
|
console.log(` History: ${settings.retainHistory ? 'ON' : 'OFF'}`);
|
|
332
|
-
console.log(` Messages: ${messages.length}`);
|
|
333
|
-
console.log(` Tools: ${
|
|
334
|
-
settings.selectedTools.length > 0
|
|
335
|
-
? settings.selectedTools.join(', ')
|
|
336
|
-
: 'Auto-tools mode'
|
|
337
|
-
}`);
|
|
290
|
+
console.log(` Messages: ${history.messages.length}`);
|
|
291
|
+
console.log(` Tools: ${settings.selectedTools.length > 0 ? settings.selectedTools.join(', ') : 'Auto-tools mode'}`);
|
|
338
292
|
}
|
|
339
293
|
|
|
340
|
-
//
|
|
294
|
+
// ==================== AUTH MENU ====================
|
|
341
295
|
async function showAuthMenu() {
|
|
342
296
|
console.log('\n========================================');
|
|
343
297
|
console.log(' Authentication Menu');
|
|
@@ -357,50 +311,25 @@ async function main() {
|
|
|
357
311
|
const choice = await prompt('Select option (1-9): ');
|
|
358
312
|
|
|
359
313
|
switch (choice.trim()) {
|
|
360
|
-
case '1':
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
case '
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
case '
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
await refreshSession();
|
|
371
|
-
break;
|
|
372
|
-
case '5':
|
|
373
|
-
await getEvmAddress();
|
|
374
|
-
break;
|
|
375
|
-
case '6':
|
|
376
|
-
await getSolanaAddress();
|
|
377
|
-
break;
|
|
378
|
-
case '7':
|
|
379
|
-
await getBtcAddresses();
|
|
380
|
-
break;
|
|
381
|
-
case '8':
|
|
382
|
-
await doLogout();
|
|
383
|
-
break;
|
|
384
|
-
case '9':
|
|
385
|
-
return;
|
|
386
|
-
default:
|
|
387
|
-
console.log('Invalid option');
|
|
314
|
+
case '1': await getApiKey(); break;
|
|
315
|
+
case '2': await getVaultInfo(); break;
|
|
316
|
+
case '3': showSessionInfo(); break;
|
|
317
|
+
case '4': await refreshSession(); break;
|
|
318
|
+
case '5': await getEvmAddress(); break;
|
|
319
|
+
case '6': await getSolanaAddress(); break;
|
|
320
|
+
case '7': await getBtcAddresses(); break;
|
|
321
|
+
case '8': await doLogout(); break;
|
|
322
|
+
case '9': return;
|
|
323
|
+
default: console.log('Invalid option');
|
|
388
324
|
}
|
|
389
325
|
|
|
390
|
-
// Show menu again after action
|
|
391
326
|
await showAuthMenu();
|
|
392
327
|
}
|
|
393
328
|
|
|
394
329
|
async function getApiKey() {
|
|
395
330
|
console.log('\nFetching API key...');
|
|
396
|
-
if (settings.debug) {
|
|
397
|
-
console.log('[DEBUG] Calling authSdk.getVaultApiKey()...');
|
|
398
|
-
}
|
|
399
331
|
try {
|
|
400
332
|
const apiKey = await authSdk.getVaultApiKey();
|
|
401
|
-
if (settings.debug) {
|
|
402
|
-
console.log('[DEBUG] Raw response:', JSON.stringify(apiKey, null, 2));
|
|
403
|
-
}
|
|
404
333
|
console.log('\n========================================');
|
|
405
334
|
console.log(' YOUR API KEY');
|
|
406
335
|
console.log('========================================');
|
|
@@ -410,27 +339,15 @@ async function main() {
|
|
|
410
339
|
console.log('========================================');
|
|
411
340
|
console.log('');
|
|
412
341
|
console.log('IMPORTANT: Store this key securely!');
|
|
413
|
-
console.log('You can use this key with the regular CLI (simple-cli.js)');
|
|
414
|
-
console.log('Set it as HUSTLE_API_KEY in your environment.');
|
|
415
342
|
} catch (error) {
|
|
416
343
|
console.error('Error fetching API key:', error.message);
|
|
417
|
-
if (settings.debug && error.stack) {
|
|
418
|
-
console.error('[DEBUG] Stack:', error.stack);
|
|
419
|
-
}
|
|
420
344
|
}
|
|
421
345
|
}
|
|
422
346
|
|
|
423
347
|
async function getVaultInfo() {
|
|
424
348
|
console.log('\nFetching vault info...');
|
|
425
|
-
if (settings.debug) {
|
|
426
|
-
console.log('[DEBUG] Calling authSdk.getVaultInfo()...');
|
|
427
|
-
}
|
|
428
349
|
try {
|
|
429
350
|
const vaultInfo = await authSdk.getVaultInfo();
|
|
430
|
-
if (settings.debug) {
|
|
431
|
-
console.log('[DEBUG] Raw response:');
|
|
432
|
-
console.log(JSON.stringify(vaultInfo, null, 2));
|
|
433
|
-
}
|
|
434
351
|
console.log('\n========================================');
|
|
435
352
|
console.log(' VAULT INFO');
|
|
436
353
|
console.log('========================================');
|
|
@@ -445,52 +362,31 @@ async function main() {
|
|
|
445
362
|
}
|
|
446
363
|
if (vaultInfo.btcAddresses) {
|
|
447
364
|
console.log(' BTC Addresses:');
|
|
448
|
-
if (vaultInfo.btcAddresses.p2pkh) {
|
|
449
|
-
|
|
450
|
-
}
|
|
451
|
-
if (vaultInfo.btcAddresses.p2wpkh) {
|
|
452
|
-
console.log(` P2WPKH: ${vaultInfo.btcAddresses.p2wpkh}`);
|
|
453
|
-
}
|
|
454
|
-
if (vaultInfo.btcAddresses.p2tr) {
|
|
455
|
-
console.log(` P2TR: ${vaultInfo.btcAddresses.p2tr}`);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
if (vaultInfo.createdAt) {
|
|
459
|
-
console.log(` Created At: ${vaultInfo.createdAt}`);
|
|
460
|
-
}
|
|
461
|
-
if (vaultInfo.created_by) {
|
|
462
|
-
console.log(` Created By: ${vaultInfo.created_by}`);
|
|
365
|
+
if (vaultInfo.btcAddresses.p2pkh) console.log(` P2PKH: ${vaultInfo.btcAddresses.p2pkh}`);
|
|
366
|
+
if (vaultInfo.btcAddresses.p2wpkh) console.log(` P2WPKH: ${vaultInfo.btcAddresses.p2wpkh}`);
|
|
367
|
+
if (vaultInfo.btcAddresses.p2tr) console.log(` P2TR: ${vaultInfo.btcAddresses.p2tr}`);
|
|
463
368
|
}
|
|
369
|
+
if (vaultInfo.createdAt) console.log(` Created At: ${vaultInfo.createdAt}`);
|
|
464
370
|
console.log('');
|
|
465
371
|
console.log('========================================');
|
|
466
372
|
} catch (error) {
|
|
467
373
|
console.error('Error fetching vault info:', error.message);
|
|
468
|
-
if (settings.debug && error.stack) {
|
|
469
|
-
console.error('[DEBUG] Stack:', error.stack);
|
|
470
|
-
}
|
|
471
374
|
}
|
|
472
375
|
}
|
|
473
376
|
|
|
474
377
|
function showSessionInfo() {
|
|
475
|
-
|
|
476
|
-
console.log('[DEBUG] Calling authSdk.getSession()...');
|
|
477
|
-
}
|
|
478
|
-
const session = authSdk.getSession();
|
|
479
|
-
if (settings.debug) {
|
|
480
|
-
console.log('[DEBUG] Raw response:');
|
|
481
|
-
console.log(JSON.stringify(session, null, 2));
|
|
482
|
-
}
|
|
378
|
+
const sess = authSdk.getSession();
|
|
483
379
|
console.log('\n========================================');
|
|
484
380
|
console.log(' SESSION INFO');
|
|
485
381
|
console.log('========================================');
|
|
486
382
|
console.log('');
|
|
487
|
-
if (
|
|
488
|
-
console.log(` Identifier: ${
|
|
489
|
-
console.log(` Vault ID: ${
|
|
490
|
-
console.log(` App ID: ${
|
|
491
|
-
console.log(` Auth Type: ${
|
|
492
|
-
console.log(` Expires At: ${
|
|
493
|
-
console.log(` Auth Token: ${
|
|
383
|
+
if (sess) {
|
|
384
|
+
console.log(` Identifier: ${sess.user?.identifier || 'N/A'}`);
|
|
385
|
+
console.log(` Vault ID: ${sess.user?.vaultId || 'N/A'}`);
|
|
386
|
+
console.log(` App ID: ${sess.appId || 'N/A'}`);
|
|
387
|
+
console.log(` Auth Type: ${sess.authType || 'N/A'}`);
|
|
388
|
+
console.log(` Expires At: ${sess.expiresAt ? new Date(sess.expiresAt).toISOString() : 'N/A'}`);
|
|
389
|
+
console.log(` Auth Token: ${sess.authToken ? sess.authToken.substring(0, 20) + '...' : 'N/A'}`);
|
|
494
390
|
} else {
|
|
495
391
|
console.log(' No active session');
|
|
496
392
|
}
|
|
@@ -500,15 +396,8 @@ async function main() {
|
|
|
500
396
|
|
|
501
397
|
async function refreshSession() {
|
|
502
398
|
console.log('\nRefreshing session...');
|
|
503
|
-
if (settings.debug) {
|
|
504
|
-
console.log('[DEBUG] Calling authSdk.refreshSession()...');
|
|
505
|
-
}
|
|
506
399
|
try {
|
|
507
400
|
const newSession = await authSdk.refreshSession();
|
|
508
|
-
if (settings.debug) {
|
|
509
|
-
console.log('[DEBUG] Raw response:');
|
|
510
|
-
console.log(JSON.stringify(newSession, null, 2));
|
|
511
|
-
}
|
|
512
401
|
if (newSession) {
|
|
513
402
|
console.log('Session refreshed successfully!');
|
|
514
403
|
console.log(`New expiry: ${new Date(newSession.expiresAt).toISOString()}`);
|
|
@@ -517,23 +406,13 @@ async function main() {
|
|
|
517
406
|
}
|
|
518
407
|
} catch (error) {
|
|
519
408
|
console.error('Error refreshing session:', error.message);
|
|
520
|
-
if (settings.debug && error.stack) {
|
|
521
|
-
console.error('[DEBUG] Stack:', error.stack);
|
|
522
|
-
}
|
|
523
409
|
}
|
|
524
410
|
}
|
|
525
411
|
|
|
526
412
|
async function getEvmAddress() {
|
|
527
413
|
console.log('\nFetching EVM address...');
|
|
528
|
-
if (settings.debug) {
|
|
529
|
-
console.log('[DEBUG] Calling authSdk.getVaultInfo() for EVM address...');
|
|
530
|
-
}
|
|
531
414
|
try {
|
|
532
415
|
const vaultInfo = await authSdk.getVaultInfo();
|
|
533
|
-
if (settings.debug) {
|
|
534
|
-
console.log('[DEBUG] Raw response:');
|
|
535
|
-
console.log(JSON.stringify(vaultInfo, null, 2));
|
|
536
|
-
}
|
|
537
416
|
if (vaultInfo.evmAddress) {
|
|
538
417
|
console.log('\n========================================');
|
|
539
418
|
console.log(' EVM ADDRESS');
|
|
@@ -547,23 +426,13 @@ async function main() {
|
|
|
547
426
|
}
|
|
548
427
|
} catch (error) {
|
|
549
428
|
console.error('Error fetching EVM address:', error.message);
|
|
550
|
-
if (settings.debug && error.stack) {
|
|
551
|
-
console.error('[DEBUG] Stack:', error.stack);
|
|
552
|
-
}
|
|
553
429
|
}
|
|
554
430
|
}
|
|
555
431
|
|
|
556
432
|
async function getSolanaAddress() {
|
|
557
433
|
console.log('\nFetching Solana address...');
|
|
558
|
-
if (settings.debug) {
|
|
559
|
-
console.log('[DEBUG] Calling authSdk.getVaultInfo() for Solana address...');
|
|
560
|
-
}
|
|
561
434
|
try {
|
|
562
435
|
const vaultInfo = await authSdk.getVaultInfo();
|
|
563
|
-
if (settings.debug) {
|
|
564
|
-
console.log('[DEBUG] Raw response:');
|
|
565
|
-
console.log(JSON.stringify(vaultInfo, null, 2));
|
|
566
|
-
}
|
|
567
436
|
const solanaAddr = vaultInfo.solanaAddress || vaultInfo.address;
|
|
568
437
|
if (solanaAddr) {
|
|
569
438
|
console.log('\n========================================');
|
|
@@ -578,42 +447,13 @@ async function main() {
|
|
|
578
447
|
}
|
|
579
448
|
} catch (error) {
|
|
580
449
|
console.error('Error fetching Solana address:', error.message);
|
|
581
|
-
if (settings.debug && error.stack) {
|
|
582
|
-
console.error('[DEBUG] Stack:', error.stack);
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
async function doLogout() {
|
|
588
|
-
console.log('\nLogging out...');
|
|
589
|
-
if (settings.debug) {
|
|
590
|
-
console.log('[DEBUG] Calling authSdk.logout()...');
|
|
591
|
-
}
|
|
592
|
-
try {
|
|
593
|
-
authSdk.logout();
|
|
594
|
-
console.log('Logged out successfully.');
|
|
595
|
-
console.log('Session cleared. Exiting CLI...');
|
|
596
|
-
rl.close();
|
|
597
|
-
process.exit(0);
|
|
598
|
-
} catch (error) {
|
|
599
|
-
console.error('Error during logout:', error.message);
|
|
600
|
-
if (settings.debug && error.stack) {
|
|
601
|
-
console.error('[DEBUG] Stack:', error.stack);
|
|
602
|
-
}
|
|
603
450
|
}
|
|
604
451
|
}
|
|
605
452
|
|
|
606
453
|
async function getBtcAddresses() {
|
|
607
454
|
console.log('\nFetching BTC addresses...');
|
|
608
|
-
if (settings.debug) {
|
|
609
|
-
console.log('[DEBUG] Calling authSdk.getVaultInfo() for BTC addresses...');
|
|
610
|
-
}
|
|
611
455
|
try {
|
|
612
456
|
const vaultInfo = await authSdk.getVaultInfo();
|
|
613
|
-
if (settings.debug) {
|
|
614
|
-
console.log('[DEBUG] Raw response:');
|
|
615
|
-
console.log(JSON.stringify(vaultInfo, null, 2));
|
|
616
|
-
}
|
|
617
457
|
if (vaultInfo.btcAddresses || vaultInfo.btcPubkey) {
|
|
618
458
|
console.log('\n========================================');
|
|
619
459
|
console.log(' BTC ADDRESSES');
|
|
@@ -624,15 +464,9 @@ async function main() {
|
|
|
624
464
|
console.log('');
|
|
625
465
|
}
|
|
626
466
|
if (vaultInfo.btcAddresses) {
|
|
627
|
-
if (vaultInfo.btcAddresses.p2pkh) {
|
|
628
|
-
|
|
629
|
-
}
|
|
630
|
-
if (vaultInfo.btcAddresses.p2wpkh) {
|
|
631
|
-
console.log(` P2WPKH (SegWit): ${vaultInfo.btcAddresses.p2wpkh}`);
|
|
632
|
-
}
|
|
633
|
-
if (vaultInfo.btcAddresses.p2tr) {
|
|
634
|
-
console.log(` P2TR (Taproot): ${vaultInfo.btcAddresses.p2tr}`);
|
|
635
|
-
}
|
|
467
|
+
if (vaultInfo.btcAddresses.p2pkh) console.log(` P2PKH (Legacy): ${vaultInfo.btcAddresses.p2pkh}`);
|
|
468
|
+
if (vaultInfo.btcAddresses.p2wpkh) console.log(` P2WPKH (SegWit): ${vaultInfo.btcAddresses.p2wpkh}`);
|
|
469
|
+
if (vaultInfo.btcAddresses.p2tr) console.log(` P2TR (Taproot): ${vaultInfo.btcAddresses.p2tr}`);
|
|
636
470
|
}
|
|
637
471
|
console.log('');
|
|
638
472
|
console.log('========================================');
|
|
@@ -641,13 +475,145 @@ async function main() {
|
|
|
641
475
|
}
|
|
642
476
|
} catch (error) {
|
|
643
477
|
console.error('Error fetching BTC addresses:', error.message);
|
|
644
|
-
|
|
645
|
-
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
async function doLogout() {
|
|
482
|
+
console.log('\nLogging out...');
|
|
483
|
+
try {
|
|
484
|
+
authSdk.logout();
|
|
485
|
+
console.log('Logged out successfully.');
|
|
486
|
+
console.log('Session cleared. Exiting CLI...');
|
|
487
|
+
rl.close();
|
|
488
|
+
process.exit(0);
|
|
489
|
+
} catch (error) {
|
|
490
|
+
console.error('Error during logout:', error.message);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// ==================== STREAM RESPONSE ====================
|
|
495
|
+
async function streamResponse(msgs) {
|
|
496
|
+
let fullText = '';
|
|
497
|
+
let toolCalls = [];
|
|
498
|
+
let firstChunk = false;
|
|
499
|
+
|
|
500
|
+
process.stdout.write('\nAgent Hustle: ');
|
|
501
|
+
startSpinner();
|
|
502
|
+
|
|
503
|
+
try {
|
|
504
|
+
const streamOptions = {
|
|
505
|
+
messages: msgs,
|
|
506
|
+
processChunks: true
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
if (settings.model) {
|
|
510
|
+
streamOptions.model = settings.model;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if (settings.selectedTools.length > 0) {
|
|
514
|
+
streamOptions.selectedToolCategories = settings.selectedTools;
|
|
515
|
+
} else if (lastIntentContext) {
|
|
516
|
+
streamOptions.intentContext = lastIntentContext;
|
|
646
517
|
}
|
|
518
|
+
|
|
519
|
+
const stream = client.chatStream(streamOptions);
|
|
520
|
+
|
|
521
|
+
for await (const chunk of stream) {
|
|
522
|
+
if ('type' in chunk) {
|
|
523
|
+
switch (chunk.type) {
|
|
524
|
+
case 'text':
|
|
525
|
+
if (!firstChunk) {
|
|
526
|
+
stopSpinner();
|
|
527
|
+
firstChunk = true;
|
|
528
|
+
}
|
|
529
|
+
process.stdout.write(chunk.value);
|
|
530
|
+
fullText += chunk.value;
|
|
531
|
+
break;
|
|
532
|
+
|
|
533
|
+
case 'intent_context':
|
|
534
|
+
if (chunk.value?.intentContext) {
|
|
535
|
+
lastIntentContext = chunk.value.intentContext;
|
|
536
|
+
if (settings.debug) {
|
|
537
|
+
console.log('[DEBUG] Captured intent context:',
|
|
538
|
+
`activeIntent="${lastIntentContext.activeIntent || 'general'}", ` +
|
|
539
|
+
`categories=[${lastIntentContext.categories?.join(', ') || 'none'}]`);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
break;
|
|
543
|
+
|
|
544
|
+
case 'tool_call':
|
|
545
|
+
if (!firstChunk) {
|
|
546
|
+
stopSpinner();
|
|
547
|
+
firstChunk = true;
|
|
548
|
+
}
|
|
549
|
+
toolCalls.push(chunk.value);
|
|
550
|
+
break;
|
|
551
|
+
|
|
552
|
+
case 'finish':
|
|
553
|
+
stopSpinner();
|
|
554
|
+
process.stdout.write('\n');
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
} catch (error) {
|
|
560
|
+
stopSpinner();
|
|
561
|
+
console.error(`\nError: ${error.message}`);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (toolCalls.length > 0) {
|
|
565
|
+
console.log('\nTools used:');
|
|
566
|
+
toolCalls.forEach((tool, i) => {
|
|
567
|
+
console.log(`${i+1}. ${tool.toolName || 'Unknown tool'} (ID: ${tool.toolCallId || 'unknown'})`);
|
|
568
|
+
if (settings.debug && tool.args) {
|
|
569
|
+
console.log(` Args: ${JSON.stringify(tool.args)}`);
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
return fullText;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// ==================== NON-STREAMING RESPONSE ====================
|
|
578
|
+
async function nonStreamResponse(msgs) {
|
|
579
|
+
console.log('\nAgent Hustle is thinking...');
|
|
580
|
+
|
|
581
|
+
try {
|
|
582
|
+
const chatOptions = {};
|
|
583
|
+
|
|
584
|
+
if (settings.model) {
|
|
585
|
+
chatOptions.model = settings.model;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
if (settings.selectedTools.length > 0) {
|
|
589
|
+
chatOptions.selectedToolCategories = settings.selectedTools;
|
|
590
|
+
} else if (lastIntentContext) {
|
|
591
|
+
chatOptions.intentContext = lastIntentContext;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const response = await client.chat(msgs, chatOptions);
|
|
595
|
+
|
|
596
|
+
if (response.intentContext?.intentContext) {
|
|
597
|
+
lastIntentContext = response.intentContext.intentContext;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
console.log(`\nAgent Hustle: ${response.content}`);
|
|
601
|
+
|
|
602
|
+
if (response.toolCalls && response.toolCalls.length > 0) {
|
|
603
|
+
console.log('\nTools used:');
|
|
604
|
+
response.toolCalls.forEach((tool, i) => {
|
|
605
|
+
console.log(`${i+1}. ${tool.toolName || 'Unknown'}`);
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return response.content;
|
|
610
|
+
} catch (error) {
|
|
611
|
+
console.error(`\nError: ${error.message}`);
|
|
612
|
+
return '';
|
|
647
613
|
}
|
|
648
614
|
}
|
|
649
615
|
|
|
650
|
-
//
|
|
616
|
+
// ==================== PROCESS COMMANDS ====================
|
|
651
617
|
async function processCommand(command) {
|
|
652
618
|
if (command === '/help') {
|
|
653
619
|
showHelp();
|
|
@@ -664,10 +630,10 @@ async function main() {
|
|
|
664
630
|
return true;
|
|
665
631
|
}
|
|
666
632
|
|
|
667
|
-
if (command === '/clear') {
|
|
668
|
-
|
|
633
|
+
if (command === '/reset' || command === '/clear') {
|
|
634
|
+
resetHistory();
|
|
635
|
+
history = { messages: [], created: new Date().toISOString() };
|
|
669
636
|
lastIntentContext = null;
|
|
670
|
-
console.log('Conversation history cleared.');
|
|
671
637
|
return true;
|
|
672
638
|
}
|
|
673
639
|
|
|
@@ -675,7 +641,6 @@ async function main() {
|
|
|
675
641
|
console.log('Goodbye!');
|
|
676
642
|
rl.close();
|
|
677
643
|
process.exit(0);
|
|
678
|
-
return true;
|
|
679
644
|
}
|
|
680
645
|
|
|
681
646
|
if (command.startsWith('/stream')) {
|
|
@@ -721,7 +686,15 @@ async function main() {
|
|
|
721
686
|
console.log('History retention disabled');
|
|
722
687
|
}
|
|
723
688
|
} else {
|
|
724
|
-
console.log(
|
|
689
|
+
console.log(`\nHistory is ${settings.retainHistory ? 'ON' : 'OFF'}`);
|
|
690
|
+
console.log(`Conversation has ${history.messages.length} messages.`);
|
|
691
|
+
if (history.messages.length > 0) {
|
|
692
|
+
console.log('Recent:');
|
|
693
|
+
history.messages.slice(-4).forEach((m) => {
|
|
694
|
+
const preview = m.content.substring(0, 60) + (m.content.length > 60 ? '...' : '');
|
|
695
|
+
console.log(` ${m.role}: ${preview}`);
|
|
696
|
+
});
|
|
697
|
+
}
|
|
725
698
|
}
|
|
726
699
|
return true;
|
|
727
700
|
}
|
|
@@ -771,9 +744,9 @@ async function main() {
|
|
|
771
744
|
console.log('\n=== Tool Categories ===\n');
|
|
772
745
|
tools.forEach((tool) => {
|
|
773
746
|
const isSelected = settings.selectedTools.includes(tool.id);
|
|
774
|
-
const status = isSelected ? '
|
|
747
|
+
const status = isSelected ? '[x]' : '[ ]';
|
|
775
748
|
console.log(`${status} ${tool.title} (${tool.id})`);
|
|
776
|
-
console.log(`
|
|
749
|
+
console.log(` ${tool.description}`);
|
|
777
750
|
});
|
|
778
751
|
console.log('\nCurrently selected:',
|
|
779
752
|
settings.selectedTools.length > 0
|
|
@@ -799,6 +772,8 @@ async function main() {
|
|
|
799
772
|
settings.selectedTools.push(toolId);
|
|
800
773
|
lastIntentContext = null;
|
|
801
774
|
console.log(`Added: ${toolId}`);
|
|
775
|
+
} else {
|
|
776
|
+
console.log(`Already added: ${toolId}`);
|
|
802
777
|
}
|
|
803
778
|
return true;
|
|
804
779
|
}
|
|
@@ -808,6 +783,8 @@ async function main() {
|
|
|
808
783
|
if (index > -1) {
|
|
809
784
|
settings.selectedTools.splice(index, 1);
|
|
810
785
|
console.log(`Removed: ${toolId}`);
|
|
786
|
+
} else {
|
|
787
|
+
console.log(`Not found: ${toolId}`);
|
|
811
788
|
}
|
|
812
789
|
return true;
|
|
813
790
|
}
|
|
@@ -818,9 +795,17 @@ async function main() {
|
|
|
818
795
|
return false;
|
|
819
796
|
}
|
|
820
797
|
|
|
821
|
-
//
|
|
798
|
+
// ==================== CHAT LOOP ====================
|
|
822
799
|
async function chat() {
|
|
823
800
|
rl.question('\nYou: ', async (input) => {
|
|
801
|
+
input = input.trim();
|
|
802
|
+
|
|
803
|
+
if (!input) {
|
|
804
|
+
chat();
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// Process commands
|
|
824
809
|
if (input.startsWith('/')) {
|
|
825
810
|
const isCommand = await processCommand(input);
|
|
826
811
|
if (isCommand) {
|
|
@@ -829,75 +814,43 @@ async function main() {
|
|
|
829
814
|
}
|
|
830
815
|
}
|
|
831
816
|
|
|
817
|
+
// Handle exit/quit without slash
|
|
832
818
|
if (input.toLowerCase() === 'exit' || input.toLowerCase() === 'quit') {
|
|
833
819
|
console.log('Goodbye!');
|
|
834
820
|
rl.close();
|
|
835
821
|
return;
|
|
836
822
|
}
|
|
837
823
|
|
|
838
|
-
|
|
824
|
+
// Build message list based on history retention setting
|
|
825
|
+
const currentMessages = settings.retainHistory ? [...history.messages] : [];
|
|
839
826
|
currentMessages.push({ role: 'user', content: input });
|
|
840
827
|
|
|
841
|
-
|
|
842
|
-
|
|
828
|
+
// Send message
|
|
829
|
+
let response;
|
|
830
|
+
if (settings.stream) {
|
|
831
|
+
response = await streamResponse(currentMessages);
|
|
832
|
+
} else {
|
|
833
|
+
response = await nonStreamResponse(currentMessages);
|
|
843
834
|
}
|
|
844
835
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
} else {
|
|
851
|
-
const chatOptions = {};
|
|
852
|
-
|
|
853
|
-
if (settings.model) {
|
|
854
|
-
chatOptions.model = settings.model;
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
if (settings.selectedTools.length > 0) {
|
|
858
|
-
chatOptions.selectedToolCategories = settings.selectedTools;
|
|
859
|
-
} else if (lastIntentContext) {
|
|
860
|
-
chatOptions.intentContext = lastIntentContext;
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
const response = await client.chat(currentMessages, chatOptions);
|
|
864
|
-
|
|
865
|
-
if (response.intentContext?.intentContext) {
|
|
866
|
-
lastIntentContext = response.intentContext.intentContext;
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
console.log(`\nAgent: ${response.content}`);
|
|
870
|
-
|
|
871
|
-
if (response.toolCalls && response.toolCalls.length > 0) {
|
|
872
|
-
console.log('\nTools used:');
|
|
873
|
-
response.toolCalls.forEach((tool, i) => {
|
|
874
|
-
console.log(`${i+1}. ${tool.toolName || 'Unknown'}`);
|
|
875
|
-
});
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
assistantResponse = response.content;
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
if (settings.retainHistory && assistantResponse) {
|
|
882
|
-
messages.push({ role: 'user', content: input });
|
|
883
|
-
messages.push({ role: 'assistant', content: assistantResponse });
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
chat();
|
|
887
|
-
} catch (error) {
|
|
888
|
-
console.error('Error:', error.message);
|
|
889
|
-
chat();
|
|
836
|
+
// Save to history
|
|
837
|
+
if (settings.retainHistory && response) {
|
|
838
|
+
history.messages.push({ role: 'user', content: input });
|
|
839
|
+
history.messages.push({ role: 'assistant', content: response });
|
|
840
|
+
saveHistory(history);
|
|
890
841
|
}
|
|
842
|
+
|
|
843
|
+
chat();
|
|
891
844
|
});
|
|
892
845
|
}
|
|
893
846
|
|
|
894
|
-
//
|
|
847
|
+
// Show initial settings and start chat
|
|
895
848
|
console.log('Type "/help" for commands, "/auth" for auth menu, or "/exit" to quit.\n');
|
|
896
849
|
showSettings();
|
|
897
850
|
chat();
|
|
898
851
|
|
|
899
852
|
} catch (error) {
|
|
900
|
-
console.error('Error
|
|
853
|
+
console.error('Error:', error.message);
|
|
901
854
|
process.exit(1);
|
|
902
855
|
}
|
|
903
856
|
}
|