@emblemvault/agentwallet 1.1.1 → 1.3.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} +491 -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,90 @@
|
|
|
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
|
+
const hustleUrlArg = getArg(['--hustle-url']);
|
|
45
|
+
const authUrlArg = getArg(['--auth-url']);
|
|
46
|
+
const apiUrlArg = getArg(['--api-url']);
|
|
47
|
+
|
|
48
|
+
// Endpoint overrides (CLI args > env vars > defaults)
|
|
49
|
+
const hustleApiUrl = hustleUrlArg || process.env.HUSTLE_API_URL || undefined;
|
|
50
|
+
const authUrl = authUrlArg || process.env.EMBLEM_AUTH_URL || undefined;
|
|
51
|
+
const apiUrl = apiUrlArg || process.env.EMBLEM_API_URL || undefined;
|
|
52
|
+
|
|
53
|
+
// Conversation history file
|
|
54
|
+
const historyFile = path.join(os.homedir(), '.emblemai-history.json');
|
|
55
|
+
|
|
56
|
+
// Load conversation history
|
|
57
|
+
function loadHistory() {
|
|
58
|
+
try {
|
|
59
|
+
if (fs.existsSync(historyFile)) {
|
|
60
|
+
const data = fs.readFileSync(historyFile, 'utf8');
|
|
61
|
+
return JSON.parse(data);
|
|
62
|
+
}
|
|
63
|
+
} catch (e) {
|
|
64
|
+
// Ignore errors, start fresh
|
|
65
|
+
}
|
|
66
|
+
return { messages: [], created: new Date().toISOString() };
|
|
67
|
+
}
|
|
38
68
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
69
|
+
// Save conversation history
|
|
70
|
+
function saveHistory(history) {
|
|
71
|
+
history.lastUpdated = new Date().toISOString();
|
|
72
|
+
fs.writeFileSync(historyFile, JSON.stringify(history, null, 2));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Reset conversation history
|
|
76
|
+
function resetHistory() {
|
|
77
|
+
if (fs.existsSync(historyFile)) {
|
|
78
|
+
fs.unlinkSync(historyFile);
|
|
79
|
+
}
|
|
80
|
+
console.log('Conversation history cleared.');
|
|
81
|
+
}
|
|
42
82
|
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const ENV_DEBUG = process.env.DEBUG === 'true';
|
|
83
|
+
// Handle --reset flag
|
|
84
|
+
if (isReset) {
|
|
85
|
+
resetHistory();
|
|
86
|
+
process.exit(0);
|
|
87
|
+
}
|
|
49
88
|
|
|
50
89
|
// Create readline interface
|
|
51
90
|
const rl = readline.createInterface({
|
|
@@ -53,22 +92,18 @@ async function main() {
|
|
|
53
92
|
output: process.stdout
|
|
54
93
|
});
|
|
55
94
|
|
|
56
|
-
// Helper to prompt for input
|
|
57
95
|
const prompt = (question) => new Promise((resolve) => {
|
|
58
96
|
rl.question(question, resolve);
|
|
59
97
|
});
|
|
60
98
|
|
|
61
|
-
//
|
|
99
|
+
// Hidden password input
|
|
62
100
|
const promptPassword = async (question) => {
|
|
63
101
|
if (process.stdin.isTTY) {
|
|
64
102
|
process.stdout.write(question);
|
|
65
|
-
|
|
66
103
|
return new Promise((resolve) => {
|
|
67
104
|
let password = '';
|
|
68
|
-
|
|
69
105
|
const onData = (char) => {
|
|
70
106
|
char = char.toString();
|
|
71
|
-
|
|
72
107
|
switch (char) {
|
|
73
108
|
case '\n':
|
|
74
109
|
case '\r':
|
|
@@ -92,7 +127,6 @@ async function main() {
|
|
|
92
127
|
process.stdout.write('*');
|
|
93
128
|
}
|
|
94
129
|
};
|
|
95
|
-
|
|
96
130
|
process.stdin.setRawMode(true);
|
|
97
131
|
process.stdin.resume();
|
|
98
132
|
process.stdin.on('data', onData);
|
|
@@ -102,105 +136,129 @@ async function main() {
|
|
|
102
136
|
}
|
|
103
137
|
};
|
|
104
138
|
|
|
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('');
|
|
139
|
+
// Get password from args, env, file, or prompt
|
|
140
|
+
let password = passwordArg || process.env.EMBLEM_PASSWORD || process.env.AGENT_PASSWORD;
|
|
112
141
|
|
|
113
|
-
//
|
|
114
|
-
|
|
142
|
+
// Try credential file
|
|
143
|
+
if (!password) {
|
|
144
|
+
const credFile = path.join(os.homedir(), '.emblem-vault');
|
|
145
|
+
if (fs.existsSync(credFile)) {
|
|
146
|
+
password = fs.readFileSync(credFile, 'utf8').trim();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
115
149
|
|
|
150
|
+
// Prompt if still no password
|
|
116
151
|
if (!password) {
|
|
117
|
-
|
|
152
|
+
if (isAgentMode) {
|
|
153
|
+
console.error('Error: Password required in agent mode. Use -p or set EMBLEM_PASSWORD');
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
118
156
|
console.log('');
|
|
119
|
-
password = await promptPassword('Enter your password (min 16 chars): ');
|
|
157
|
+
password = await promptPassword('Enter your EmblemVault password (min 16 chars): ');
|
|
120
158
|
}
|
|
121
159
|
|
|
122
|
-
// Validate password
|
|
123
160
|
if (!password || password.length < 16) {
|
|
124
|
-
console.error('
|
|
125
|
-
console.error('Use a long, random string like an API key for security.');
|
|
161
|
+
console.error('Error: Password must be at least 16 characters.');
|
|
126
162
|
process.exit(1);
|
|
127
163
|
}
|
|
128
164
|
|
|
129
|
-
|
|
130
|
-
|
|
165
|
+
// Authenticate
|
|
166
|
+
if (!isAgentMode) {
|
|
167
|
+
console.log('');
|
|
168
|
+
console.log('Authenticating with Agent Hustle...');
|
|
169
|
+
}
|
|
131
170
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
171
|
+
const authSdkConfig = {
|
|
172
|
+
appId: 'emblem-agent-wallet',
|
|
173
|
+
persistSession: false,
|
|
174
|
+
};
|
|
175
|
+
if (authUrl) authSdkConfig.authUrl = authUrl;
|
|
176
|
+
if (apiUrl) authSdkConfig.apiUrl = apiUrl;
|
|
135
177
|
|
|
136
|
-
|
|
137
|
-
const sdkConfig = {
|
|
138
|
-
appId: ENV_APP_ID,
|
|
139
|
-
persistSession: false, // No localStorage in Node.js
|
|
140
|
-
};
|
|
178
|
+
const authSdk = new EmblemAuthSDK(authSdkConfig);
|
|
141
179
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
180
|
+
const session = await authSdk.authenticatePassword({ password });
|
|
181
|
+
if (!session) {
|
|
182
|
+
throw new Error('Authentication failed');
|
|
183
|
+
}
|
|
145
184
|
|
|
146
|
-
|
|
185
|
+
// Settings (runtime state)
|
|
186
|
+
const settings = {
|
|
187
|
+
debug: initialDebug,
|
|
188
|
+
stream: !initialStream ? true : initialStream, // Default ON
|
|
189
|
+
retainHistory: true,
|
|
190
|
+
selectedTools: [],
|
|
191
|
+
model: null,
|
|
192
|
+
};
|
|
147
193
|
|
|
148
|
-
|
|
149
|
-
|
|
194
|
+
const hustleClientConfig = {
|
|
195
|
+
sdk: authSdk,
|
|
196
|
+
debug: settings.debug,
|
|
197
|
+
};
|
|
198
|
+
if (hustleApiUrl) hustleClientConfig.hustleApiUrl = hustleApiUrl;
|
|
150
199
|
|
|
151
|
-
|
|
152
|
-
throw new Error('Authentication failed - no session returned');
|
|
153
|
-
}
|
|
200
|
+
const client = new HustleIncognitoClient(hustleClientConfig);
|
|
154
201
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
202
|
+
// Intent context for auto-tools mode
|
|
203
|
+
let lastIntentContext = null;
|
|
204
|
+
|
|
205
|
+
// Load existing history (resume by default)
|
|
206
|
+
let history = loadHistory();
|
|
160
207
|
|
|
161
|
-
|
|
162
|
-
|
|
208
|
+
// ==================== AGENT MODE ====================
|
|
209
|
+
if (isAgentMode) {
|
|
210
|
+
if (!messageArg) {
|
|
211
|
+
console.error('Error: Message required in agent mode. Use -m "your message"');
|
|
212
|
+
process.exit(1);
|
|
163
213
|
}
|
|
164
214
|
|
|
165
|
-
|
|
215
|
+
console.log('Agent Hustle is thinking.');
|
|
166
216
|
|
|
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
|
-
}
|
|
217
|
+
// Add user message to history
|
|
218
|
+
history.messages.push({ role: 'user', content: messageArg });
|
|
175
219
|
|
|
176
|
-
|
|
177
|
-
|
|
220
|
+
// Progress indicator - output a dot every 5 seconds to show it's not hung
|
|
221
|
+
const progressInterval = setInterval(() => {
|
|
222
|
+
process.stdout.write('.');
|
|
223
|
+
}, 5000);
|
|
178
224
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
debug: initialDebugMode || ENV_DEBUG,
|
|
182
|
-
stream: initialStreamMode,
|
|
183
|
-
selectedTools: [],
|
|
184
|
-
retainHistory: true,
|
|
185
|
-
model: null,
|
|
186
|
-
};
|
|
225
|
+
try {
|
|
226
|
+
const response = await client.chat(history.messages);
|
|
187
227
|
|
|
188
|
-
|
|
189
|
-
|
|
228
|
+
// Stop progress indicator
|
|
229
|
+
clearInterval(progressInterval);
|
|
190
230
|
|
|
191
|
-
|
|
192
|
-
|
|
231
|
+
// Add assistant response to history
|
|
232
|
+
history.messages.push({ role: 'assistant', content: response.content });
|
|
233
|
+
saveHistory(history);
|
|
234
|
+
|
|
235
|
+
// Output response (for agent to capture)
|
|
236
|
+
console.log(response.content);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
clearInterval(progressInterval);
|
|
239
|
+
console.error('Error:', error.message);
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
rl.close();
|
|
244
|
+
process.exit(0);
|
|
245
|
+
}
|
|
193
246
|
|
|
194
|
-
//
|
|
247
|
+
// ==================== INTERACTIVE MODE ====================
|
|
248
|
+
console.log('');
|
|
249
|
+
console.log('========================================');
|
|
250
|
+
console.log(' Agent Hustle CLI');
|
|
251
|
+
console.log('========================================');
|
|
252
|
+
console.log('');
|
|
253
|
+
|
|
254
|
+
// Spinner
|
|
195
255
|
const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
196
256
|
let spinnerInterval = null;
|
|
197
257
|
let spinnerIndex = 0;
|
|
198
|
-
const hideCursor = '\x1B[?25l';
|
|
199
|
-
const showCursor = '\x1B[?25h';
|
|
200
258
|
|
|
201
259
|
function startSpinner() {
|
|
202
260
|
spinnerIndex = 0;
|
|
203
|
-
process.stdout.write(
|
|
261
|
+
process.stdout.write('\x1B[?25l' + spinnerFrames[0]);
|
|
204
262
|
spinnerInterval = setInterval(() => {
|
|
205
263
|
process.stdout.write('\b' + spinnerFrames[spinnerIndex]);
|
|
206
264
|
spinnerIndex = (spinnerIndex + 1) % spinnerFrames.length;
|
|
@@ -211,133 +269,53 @@ async function main() {
|
|
|
211
269
|
if (spinnerInterval) {
|
|
212
270
|
clearInterval(spinnerInterval);
|
|
213
271
|
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}`);
|
|
272
|
+
process.stdout.write('\b \b\x1B[?25h');
|
|
286
273
|
}
|
|
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
|
-
});
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
return fullText;
|
|
299
274
|
}
|
|
300
275
|
|
|
301
|
-
//
|
|
276
|
+
// ==================== HELP ====================
|
|
302
277
|
function showHelp() {
|
|
303
|
-
console.log('\
|
|
304
|
-
console.log(' /help
|
|
305
|
-
console.log(' /settings
|
|
306
|
-
console.log(' /auth
|
|
278
|
+
console.log('\nCommands:');
|
|
279
|
+
console.log(' /help - Show this help');
|
|
280
|
+
console.log(' /settings - Show current settings');
|
|
281
|
+
console.log(' /auth - Open auth menu (API key, addresses, etc.)');
|
|
307
282
|
console.log(' /stream on|off - Toggle streaming mode');
|
|
308
283
|
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(' /
|
|
318
|
-
console.log(' /
|
|
284
|
+
console.log(' /history on|off - Toggle history retention');
|
|
285
|
+
console.log(' /reset - Clear conversation history');
|
|
286
|
+
console.log(' /models - List available models');
|
|
287
|
+
console.log(' /model <id> - Set model (or "clear" to reset)');
|
|
288
|
+
console.log(' /tools - List tool categories');
|
|
289
|
+
console.log(' /tools add|remove <id> - Manage tools');
|
|
290
|
+
console.log(' /tools clear - Enable auto-tools mode');
|
|
291
|
+
console.log(' /payment - Show PAYG billing status');
|
|
292
|
+
console.log(' /payment enable - Enable pay-as-you-go billing');
|
|
293
|
+
console.log(' /payment disable - Disable pay-as-you-go billing');
|
|
294
|
+
console.log(' /payment token <T> - Set payment token (SOL, ETH, HUSTLE, etc.)');
|
|
295
|
+
console.log(' /payment mode <M> - Set payment mode (pay_per_request, debt_accumulation)');
|
|
296
|
+
console.log(' /exit - Exit the CLI');
|
|
319
297
|
}
|
|
320
298
|
|
|
321
|
-
//
|
|
299
|
+
// ==================== SETTINGS ====================
|
|
322
300
|
function showSettings() {
|
|
323
|
-
const
|
|
301
|
+
const sess = authSdk.getSession();
|
|
324
302
|
console.log('\nCurrent settings:');
|
|
325
|
-
console.log(` App ID:
|
|
326
|
-
console.log(` Vault ID: ${
|
|
303
|
+
console.log(` App ID: emblem-agent-wallet`);
|
|
304
|
+
console.log(` Vault ID: ${sess?.user?.vaultId || 'N/A'}`);
|
|
327
305
|
console.log(` Auth Mode: Password (headless)`);
|
|
306
|
+
if (hustleApiUrl) console.log(` Hustle API: ${hustleApiUrl}`);
|
|
307
|
+
if (authUrl) console.log(` Auth URL: ${authUrl}`);
|
|
308
|
+
if (apiUrl) console.log(` API URL: ${apiUrl}`);
|
|
328
309
|
console.log(` Model: ${settings.model || 'API default'}`);
|
|
329
310
|
console.log(` Streaming: ${settings.stream ? 'ON' : 'OFF'}`);
|
|
330
311
|
console.log(` Debug: ${settings.debug ? 'ON' : 'OFF'}`);
|
|
331
312
|
console.log(` History: ${settings.retainHistory ? 'ON' : 'OFF'}`);
|
|
332
|
-
console.log(` Messages: ${messages.length}`);
|
|
333
|
-
console.log(` Tools: ${
|
|
334
|
-
|
|
335
|
-
? settings.selectedTools.join(', ')
|
|
336
|
-
: 'Auto-tools mode'
|
|
337
|
-
}`);
|
|
313
|
+
console.log(` Messages: ${history.messages.length}`);
|
|
314
|
+
console.log(` Tools: ${settings.selectedTools.length > 0 ? settings.selectedTools.join(', ') : 'Auto-tools mode'}`);
|
|
315
|
+
console.log(' PAYG: Use /payment to view billing status');
|
|
338
316
|
}
|
|
339
317
|
|
|
340
|
-
//
|
|
318
|
+
// ==================== AUTH MENU ====================
|
|
341
319
|
async function showAuthMenu() {
|
|
342
320
|
console.log('\n========================================');
|
|
343
321
|
console.log(' Authentication Menu');
|
|
@@ -357,50 +335,25 @@ async function main() {
|
|
|
357
335
|
const choice = await prompt('Select option (1-9): ');
|
|
358
336
|
|
|
359
337
|
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');
|
|
338
|
+
case '1': await getApiKey(); break;
|
|
339
|
+
case '2': await getVaultInfo(); break;
|
|
340
|
+
case '3': showSessionInfo(); break;
|
|
341
|
+
case '4': await refreshSession(); break;
|
|
342
|
+
case '5': await getEvmAddress(); break;
|
|
343
|
+
case '6': await getSolanaAddress(); break;
|
|
344
|
+
case '7': await getBtcAddresses(); break;
|
|
345
|
+
case '8': await doLogout(); break;
|
|
346
|
+
case '9': return;
|
|
347
|
+
default: console.log('Invalid option');
|
|
388
348
|
}
|
|
389
349
|
|
|
390
|
-
// Show menu again after action
|
|
391
350
|
await showAuthMenu();
|
|
392
351
|
}
|
|
393
352
|
|
|
394
353
|
async function getApiKey() {
|
|
395
354
|
console.log('\nFetching API key...');
|
|
396
|
-
if (settings.debug) {
|
|
397
|
-
console.log('[DEBUG] Calling authSdk.getVaultApiKey()...');
|
|
398
|
-
}
|
|
399
355
|
try {
|
|
400
356
|
const apiKey = await authSdk.getVaultApiKey();
|
|
401
|
-
if (settings.debug) {
|
|
402
|
-
console.log('[DEBUG] Raw response:', JSON.stringify(apiKey, null, 2));
|
|
403
|
-
}
|
|
404
357
|
console.log('\n========================================');
|
|
405
358
|
console.log(' YOUR API KEY');
|
|
406
359
|
console.log('========================================');
|
|
@@ -410,27 +363,15 @@ async function main() {
|
|
|
410
363
|
console.log('========================================');
|
|
411
364
|
console.log('');
|
|
412
365
|
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
366
|
} catch (error) {
|
|
416
367
|
console.error('Error fetching API key:', error.message);
|
|
417
|
-
if (settings.debug && error.stack) {
|
|
418
|
-
console.error('[DEBUG] Stack:', error.stack);
|
|
419
|
-
}
|
|
420
368
|
}
|
|
421
369
|
}
|
|
422
370
|
|
|
423
371
|
async function getVaultInfo() {
|
|
424
372
|
console.log('\nFetching vault info...');
|
|
425
|
-
if (settings.debug) {
|
|
426
|
-
console.log('[DEBUG] Calling authSdk.getVaultInfo()...');
|
|
427
|
-
}
|
|
428
373
|
try {
|
|
429
374
|
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
375
|
console.log('\n========================================');
|
|
435
376
|
console.log(' VAULT INFO');
|
|
436
377
|
console.log('========================================');
|
|
@@ -445,52 +386,31 @@ async function main() {
|
|
|
445
386
|
}
|
|
446
387
|
if (vaultInfo.btcAddresses) {
|
|
447
388
|
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}`);
|
|
389
|
+
if (vaultInfo.btcAddresses.p2pkh) console.log(` P2PKH: ${vaultInfo.btcAddresses.p2pkh}`);
|
|
390
|
+
if (vaultInfo.btcAddresses.p2wpkh) console.log(` P2WPKH: ${vaultInfo.btcAddresses.p2wpkh}`);
|
|
391
|
+
if (vaultInfo.btcAddresses.p2tr) console.log(` P2TR: ${vaultInfo.btcAddresses.p2tr}`);
|
|
463
392
|
}
|
|
393
|
+
if (vaultInfo.createdAt) console.log(` Created At: ${vaultInfo.createdAt}`);
|
|
464
394
|
console.log('');
|
|
465
395
|
console.log('========================================');
|
|
466
396
|
} catch (error) {
|
|
467
397
|
console.error('Error fetching vault info:', error.message);
|
|
468
|
-
if (settings.debug && error.stack) {
|
|
469
|
-
console.error('[DEBUG] Stack:', error.stack);
|
|
470
|
-
}
|
|
471
398
|
}
|
|
472
399
|
}
|
|
473
400
|
|
|
474
401
|
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
|
-
}
|
|
402
|
+
const sess = authSdk.getSession();
|
|
483
403
|
console.log('\n========================================');
|
|
484
404
|
console.log(' SESSION INFO');
|
|
485
405
|
console.log('========================================');
|
|
486
406
|
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: ${
|
|
407
|
+
if (sess) {
|
|
408
|
+
console.log(` Identifier: ${sess.user?.identifier || 'N/A'}`);
|
|
409
|
+
console.log(` Vault ID: ${sess.user?.vaultId || 'N/A'}`);
|
|
410
|
+
console.log(` App ID: ${sess.appId || 'N/A'}`);
|
|
411
|
+
console.log(` Auth Type: ${sess.authType || 'N/A'}`);
|
|
412
|
+
console.log(` Expires At: ${sess.expiresAt ? new Date(sess.expiresAt).toISOString() : 'N/A'}`);
|
|
413
|
+
console.log(` Auth Token: ${sess.authToken ? sess.authToken.substring(0, 20) + '...' : 'N/A'}`);
|
|
494
414
|
} else {
|
|
495
415
|
console.log(' No active session');
|
|
496
416
|
}
|
|
@@ -500,15 +420,8 @@ async function main() {
|
|
|
500
420
|
|
|
501
421
|
async function refreshSession() {
|
|
502
422
|
console.log('\nRefreshing session...');
|
|
503
|
-
if (settings.debug) {
|
|
504
|
-
console.log('[DEBUG] Calling authSdk.refreshSession()...');
|
|
505
|
-
}
|
|
506
423
|
try {
|
|
507
424
|
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
425
|
if (newSession) {
|
|
513
426
|
console.log('Session refreshed successfully!');
|
|
514
427
|
console.log(`New expiry: ${new Date(newSession.expiresAt).toISOString()}`);
|
|
@@ -517,23 +430,13 @@ async function main() {
|
|
|
517
430
|
}
|
|
518
431
|
} catch (error) {
|
|
519
432
|
console.error('Error refreshing session:', error.message);
|
|
520
|
-
if (settings.debug && error.stack) {
|
|
521
|
-
console.error('[DEBUG] Stack:', error.stack);
|
|
522
|
-
}
|
|
523
433
|
}
|
|
524
434
|
}
|
|
525
435
|
|
|
526
436
|
async function getEvmAddress() {
|
|
527
437
|
console.log('\nFetching EVM address...');
|
|
528
|
-
if (settings.debug) {
|
|
529
|
-
console.log('[DEBUG] Calling authSdk.getVaultInfo() for EVM address...');
|
|
530
|
-
}
|
|
531
438
|
try {
|
|
532
439
|
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
440
|
if (vaultInfo.evmAddress) {
|
|
538
441
|
console.log('\n========================================');
|
|
539
442
|
console.log(' EVM ADDRESS');
|
|
@@ -547,23 +450,13 @@ async function main() {
|
|
|
547
450
|
}
|
|
548
451
|
} catch (error) {
|
|
549
452
|
console.error('Error fetching EVM address:', error.message);
|
|
550
|
-
if (settings.debug && error.stack) {
|
|
551
|
-
console.error('[DEBUG] Stack:', error.stack);
|
|
552
|
-
}
|
|
553
453
|
}
|
|
554
454
|
}
|
|
555
455
|
|
|
556
456
|
async function getSolanaAddress() {
|
|
557
457
|
console.log('\nFetching Solana address...');
|
|
558
|
-
if (settings.debug) {
|
|
559
|
-
console.log('[DEBUG] Calling authSdk.getVaultInfo() for Solana address...');
|
|
560
|
-
}
|
|
561
458
|
try {
|
|
562
459
|
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
460
|
const solanaAddr = vaultInfo.solanaAddress || vaultInfo.address;
|
|
568
461
|
if (solanaAddr) {
|
|
569
462
|
console.log('\n========================================');
|
|
@@ -578,42 +471,13 @@ async function main() {
|
|
|
578
471
|
}
|
|
579
472
|
} catch (error) {
|
|
580
473
|
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
474
|
}
|
|
604
475
|
}
|
|
605
476
|
|
|
606
477
|
async function getBtcAddresses() {
|
|
607
478
|
console.log('\nFetching BTC addresses...');
|
|
608
|
-
if (settings.debug) {
|
|
609
|
-
console.log('[DEBUG] Calling authSdk.getVaultInfo() for BTC addresses...');
|
|
610
|
-
}
|
|
611
479
|
try {
|
|
612
480
|
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
481
|
if (vaultInfo.btcAddresses || vaultInfo.btcPubkey) {
|
|
618
482
|
console.log('\n========================================');
|
|
619
483
|
console.log(' BTC ADDRESSES');
|
|
@@ -624,15 +488,9 @@ async function main() {
|
|
|
624
488
|
console.log('');
|
|
625
489
|
}
|
|
626
490
|
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
|
-
}
|
|
491
|
+
if (vaultInfo.btcAddresses.p2pkh) console.log(` P2PKH (Legacy): ${vaultInfo.btcAddresses.p2pkh}`);
|
|
492
|
+
if (vaultInfo.btcAddresses.p2wpkh) console.log(` P2WPKH (SegWit): ${vaultInfo.btcAddresses.p2wpkh}`);
|
|
493
|
+
if (vaultInfo.btcAddresses.p2tr) console.log(` P2TR (Taproot): ${vaultInfo.btcAddresses.p2tr}`);
|
|
636
494
|
}
|
|
637
495
|
console.log('');
|
|
638
496
|
console.log('========================================');
|
|
@@ -641,13 +499,181 @@ async function main() {
|
|
|
641
499
|
}
|
|
642
500
|
} catch (error) {
|
|
643
501
|
console.error('Error fetching BTC addresses:', error.message);
|
|
644
|
-
|
|
645
|
-
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
async function doLogout() {
|
|
506
|
+
console.log('\nLogging out...');
|
|
507
|
+
try {
|
|
508
|
+
authSdk.logout();
|
|
509
|
+
console.log('Logged out successfully.');
|
|
510
|
+
console.log('Session cleared. Exiting CLI...');
|
|
511
|
+
rl.close();
|
|
512
|
+
process.exit(0);
|
|
513
|
+
} catch (error) {
|
|
514
|
+
console.error('Error during logout:', error.message);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// ==================== PAYG MANAGEMENT ====================
|
|
519
|
+
async function showPaygStatus() {
|
|
520
|
+
console.log('\nFetching PAYG billing status...');
|
|
521
|
+
try {
|
|
522
|
+
const status = await client.getPaygStatus();
|
|
523
|
+
console.log('\n========================================');
|
|
524
|
+
console.log(' PAYG Billing Status');
|
|
525
|
+
console.log('========================================');
|
|
526
|
+
console.log('');
|
|
527
|
+
console.log(` Enabled: ${status.enabled ? 'YES' : 'NO'}`);
|
|
528
|
+
console.log(` Mode: ${status.mode || 'N/A'}`);
|
|
529
|
+
console.log(` Payment Token: ${status.payment_token || 'N/A'}`);
|
|
530
|
+
console.log(` Payment Chain: ${status.payment_chain || 'N/A'}`);
|
|
531
|
+
console.log(` Blocked: ${status.is_blocked ? 'YES' : 'NO'}`);
|
|
532
|
+
console.log(` Total Debt: $${(status.total_debt_usd || 0).toFixed(4)}`);
|
|
533
|
+
console.log(` Total Paid: $${(status.total_paid_usd || 0).toFixed(4)}`);
|
|
534
|
+
console.log(` Debt Ceiling: $${(status.debt_ceiling_usd || 0).toFixed(2)}`);
|
|
535
|
+
console.log(` Pending Charges: ${status.pending_charges || 0}`);
|
|
536
|
+
console.log('');
|
|
537
|
+
if (status.available_tokens && status.available_tokens.length > 0) {
|
|
538
|
+
console.log(' Available Tokens:');
|
|
539
|
+
status.available_tokens.forEach(t => console.log(` - ${t}`));
|
|
646
540
|
}
|
|
541
|
+
console.log('');
|
|
542
|
+
console.log('========================================');
|
|
543
|
+
console.log('');
|
|
544
|
+
console.log('Commands:');
|
|
545
|
+
console.log(' /payment enable - Enable PAYG billing');
|
|
546
|
+
console.log(' /payment disable - Disable PAYG billing');
|
|
547
|
+
console.log(' /payment token <TOKEN> - Set payment token');
|
|
548
|
+
console.log(' /payment mode <MODE> - Set payment mode');
|
|
549
|
+
} catch (error) {
|
|
550
|
+
console.error('Error fetching PAYG status:', error.message);
|
|
647
551
|
}
|
|
648
552
|
}
|
|
649
553
|
|
|
650
|
-
//
|
|
554
|
+
// ==================== STREAM RESPONSE ====================
|
|
555
|
+
async function streamResponse(msgs) {
|
|
556
|
+
let fullText = '';
|
|
557
|
+
let toolCalls = [];
|
|
558
|
+
let firstChunk = false;
|
|
559
|
+
|
|
560
|
+
process.stdout.write('\nAgent Hustle: ');
|
|
561
|
+
startSpinner();
|
|
562
|
+
|
|
563
|
+
try {
|
|
564
|
+
const streamOptions = {
|
|
565
|
+
messages: msgs,
|
|
566
|
+
processChunks: true
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
if (settings.model) {
|
|
570
|
+
streamOptions.model = settings.model;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
if (settings.selectedTools.length > 0) {
|
|
574
|
+
streamOptions.selectedToolCategories = settings.selectedTools;
|
|
575
|
+
} else if (lastIntentContext) {
|
|
576
|
+
streamOptions.intentContext = lastIntentContext;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const stream = client.chatStream(streamOptions);
|
|
580
|
+
|
|
581
|
+
for await (const chunk of stream) {
|
|
582
|
+
if ('type' in chunk) {
|
|
583
|
+
switch (chunk.type) {
|
|
584
|
+
case 'text':
|
|
585
|
+
if (!firstChunk) {
|
|
586
|
+
stopSpinner();
|
|
587
|
+
firstChunk = true;
|
|
588
|
+
}
|
|
589
|
+
process.stdout.write(chunk.value);
|
|
590
|
+
fullText += chunk.value;
|
|
591
|
+
break;
|
|
592
|
+
|
|
593
|
+
case 'intent_context':
|
|
594
|
+
if (chunk.value?.intentContext) {
|
|
595
|
+
lastIntentContext = chunk.value.intentContext;
|
|
596
|
+
if (settings.debug) {
|
|
597
|
+
console.log('[DEBUG] Captured intent context:',
|
|
598
|
+
`activeIntent="${lastIntentContext.activeIntent || 'general'}", ` +
|
|
599
|
+
`categories=[${lastIntentContext.categories?.join(', ') || 'none'}]`);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
break;
|
|
603
|
+
|
|
604
|
+
case 'tool_call':
|
|
605
|
+
if (!firstChunk) {
|
|
606
|
+
stopSpinner();
|
|
607
|
+
firstChunk = true;
|
|
608
|
+
}
|
|
609
|
+
toolCalls.push(chunk.value);
|
|
610
|
+
break;
|
|
611
|
+
|
|
612
|
+
case 'finish':
|
|
613
|
+
stopSpinner();
|
|
614
|
+
process.stdout.write('\n');
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
} catch (error) {
|
|
620
|
+
stopSpinner();
|
|
621
|
+
console.error(`\nError: ${error.message}`);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
if (toolCalls.length > 0) {
|
|
625
|
+
console.log('\nTools used:');
|
|
626
|
+
toolCalls.forEach((tool, i) => {
|
|
627
|
+
console.log(`${i+1}. ${tool.toolName || 'Unknown tool'} (ID: ${tool.toolCallId || 'unknown'})`);
|
|
628
|
+
if (settings.debug && tool.args) {
|
|
629
|
+
console.log(` Args: ${JSON.stringify(tool.args)}`);
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
return fullText;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// ==================== NON-STREAMING RESPONSE ====================
|
|
638
|
+
async function nonStreamResponse(msgs) {
|
|
639
|
+
console.log('\nAgent Hustle is thinking...');
|
|
640
|
+
|
|
641
|
+
try {
|
|
642
|
+
const chatOptions = {};
|
|
643
|
+
|
|
644
|
+
if (settings.model) {
|
|
645
|
+
chatOptions.model = settings.model;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
if (settings.selectedTools.length > 0) {
|
|
649
|
+
chatOptions.selectedToolCategories = settings.selectedTools;
|
|
650
|
+
} else if (lastIntentContext) {
|
|
651
|
+
chatOptions.intentContext = lastIntentContext;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
const response = await client.chat(msgs, chatOptions);
|
|
655
|
+
|
|
656
|
+
if (response.intentContext?.intentContext) {
|
|
657
|
+
lastIntentContext = response.intentContext.intentContext;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
console.log(`\nAgent Hustle: ${response.content}`);
|
|
661
|
+
|
|
662
|
+
if (response.toolCalls && response.toolCalls.length > 0) {
|
|
663
|
+
console.log('\nTools used:');
|
|
664
|
+
response.toolCalls.forEach((tool, i) => {
|
|
665
|
+
console.log(`${i+1}. ${tool.toolName || 'Unknown'}`);
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
return response.content;
|
|
670
|
+
} catch (error) {
|
|
671
|
+
console.error(`\nError: ${error.message}`);
|
|
672
|
+
return '';
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// ==================== PROCESS COMMANDS ====================
|
|
651
677
|
async function processCommand(command) {
|
|
652
678
|
if (command === '/help') {
|
|
653
679
|
showHelp();
|
|
@@ -664,10 +690,10 @@ async function main() {
|
|
|
664
690
|
return true;
|
|
665
691
|
}
|
|
666
692
|
|
|
667
|
-
if (command === '/clear') {
|
|
668
|
-
|
|
693
|
+
if (command === '/reset' || command === '/clear') {
|
|
694
|
+
resetHistory();
|
|
695
|
+
history = { messages: [], created: new Date().toISOString() };
|
|
669
696
|
lastIntentContext = null;
|
|
670
|
-
console.log('Conversation history cleared.');
|
|
671
697
|
return true;
|
|
672
698
|
}
|
|
673
699
|
|
|
@@ -675,7 +701,6 @@ async function main() {
|
|
|
675
701
|
console.log('Goodbye!');
|
|
676
702
|
rl.close();
|
|
677
703
|
process.exit(0);
|
|
678
|
-
return true;
|
|
679
704
|
}
|
|
680
705
|
|
|
681
706
|
if (command.startsWith('/stream')) {
|
|
@@ -721,7 +746,15 @@ async function main() {
|
|
|
721
746
|
console.log('History retention disabled');
|
|
722
747
|
}
|
|
723
748
|
} else {
|
|
724
|
-
console.log(
|
|
749
|
+
console.log(`\nHistory is ${settings.retainHistory ? 'ON' : 'OFF'}`);
|
|
750
|
+
console.log(`Conversation has ${history.messages.length} messages.`);
|
|
751
|
+
if (history.messages.length > 0) {
|
|
752
|
+
console.log('Recent:');
|
|
753
|
+
history.messages.slice(-4).forEach((m) => {
|
|
754
|
+
const preview = m.content.substring(0, 60) + (m.content.length > 60 ? '...' : '');
|
|
755
|
+
console.log(` ${m.role}: ${preview}`);
|
|
756
|
+
});
|
|
757
|
+
}
|
|
725
758
|
}
|
|
726
759
|
return true;
|
|
727
760
|
}
|
|
@@ -771,9 +804,9 @@ async function main() {
|
|
|
771
804
|
console.log('\n=== Tool Categories ===\n');
|
|
772
805
|
tools.forEach((tool) => {
|
|
773
806
|
const isSelected = settings.selectedTools.includes(tool.id);
|
|
774
|
-
const status = isSelected ? '
|
|
807
|
+
const status = isSelected ? '[x]' : '[ ]';
|
|
775
808
|
console.log(`${status} ${tool.title} (${tool.id})`);
|
|
776
|
-
console.log(`
|
|
809
|
+
console.log(` ${tool.description}`);
|
|
777
810
|
});
|
|
778
811
|
console.log('\nCurrently selected:',
|
|
779
812
|
settings.selectedTools.length > 0
|
|
@@ -799,6 +832,8 @@ async function main() {
|
|
|
799
832
|
settings.selectedTools.push(toolId);
|
|
800
833
|
lastIntentContext = null;
|
|
801
834
|
console.log(`Added: ${toolId}`);
|
|
835
|
+
} else {
|
|
836
|
+
console.log(`Already added: ${toolId}`);
|
|
802
837
|
}
|
|
803
838
|
return true;
|
|
804
839
|
}
|
|
@@ -808,19 +843,89 @@ async function main() {
|
|
|
808
843
|
if (index > -1) {
|
|
809
844
|
settings.selectedTools.splice(index, 1);
|
|
810
845
|
console.log(`Removed: ${toolId}`);
|
|
846
|
+
} else {
|
|
847
|
+
console.log(`Not found: ${toolId}`);
|
|
848
|
+
}
|
|
849
|
+
return true;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (command.startsWith('/payment')) {
|
|
856
|
+
const parts = command.split(' ');
|
|
857
|
+
|
|
858
|
+
if (parts.length === 1) {
|
|
859
|
+
await showPaygStatus();
|
|
860
|
+
return true;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
const subCommand = parts[1];
|
|
864
|
+
|
|
865
|
+
if (subCommand === 'enable') {
|
|
866
|
+
try {
|
|
867
|
+
const result = await client.configurePayg({ enabled: true });
|
|
868
|
+
console.log(result.success ? 'PAYG billing enabled.' : 'Failed to enable PAYG.');
|
|
869
|
+
} catch (error) {
|
|
870
|
+
console.error('Error enabling PAYG:', error.message);
|
|
871
|
+
}
|
|
872
|
+
return true;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
if (subCommand === 'disable') {
|
|
876
|
+
try {
|
|
877
|
+
const result = await client.configurePayg({ enabled: false });
|
|
878
|
+
console.log(result.success ? 'PAYG billing disabled.' : 'Failed to disable PAYG.');
|
|
879
|
+
} catch (error) {
|
|
880
|
+
console.error('Error disabling PAYG:', error.message);
|
|
881
|
+
}
|
|
882
|
+
return true;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
if (subCommand === 'token' && parts[2]) {
|
|
886
|
+
const token = parts[2].toUpperCase();
|
|
887
|
+
try {
|
|
888
|
+
const result = await client.configurePayg({ payment_token: token });
|
|
889
|
+
console.log(result.success ? `Payment token set to: ${token}` : 'Failed to set payment token.');
|
|
890
|
+
} catch (error) {
|
|
891
|
+
console.error('Error setting payment token:', error.message);
|
|
811
892
|
}
|
|
812
893
|
return true;
|
|
813
894
|
}
|
|
814
895
|
|
|
896
|
+
if (subCommand === 'mode' && parts[2]) {
|
|
897
|
+
const mode = parts[2];
|
|
898
|
+
if (mode !== 'pay_per_request' && mode !== 'debt_accumulation') {
|
|
899
|
+
console.log('Invalid mode. Use: pay_per_request or debt_accumulation');
|
|
900
|
+
return true;
|
|
901
|
+
}
|
|
902
|
+
try {
|
|
903
|
+
const result = await client.configurePayg({ mode });
|
|
904
|
+
console.log(result.success ? `Payment mode set to: ${mode}` : 'Failed to set payment mode.');
|
|
905
|
+
} catch (error) {
|
|
906
|
+
console.error('Error setting payment mode:', error.message);
|
|
907
|
+
}
|
|
908
|
+
return true;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
console.log('Invalid /payment command. Use /payment for status, or /payment enable|disable|token|mode');
|
|
815
912
|
return true;
|
|
816
913
|
}
|
|
817
914
|
|
|
818
915
|
return false;
|
|
819
916
|
}
|
|
820
917
|
|
|
821
|
-
//
|
|
918
|
+
// ==================== CHAT LOOP ====================
|
|
822
919
|
async function chat() {
|
|
823
920
|
rl.question('\nYou: ', async (input) => {
|
|
921
|
+
input = input.trim();
|
|
922
|
+
|
|
923
|
+
if (!input) {
|
|
924
|
+
chat();
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
// Process commands
|
|
824
929
|
if (input.startsWith('/')) {
|
|
825
930
|
const isCommand = await processCommand(input);
|
|
826
931
|
if (isCommand) {
|
|
@@ -829,75 +934,43 @@ async function main() {
|
|
|
829
934
|
}
|
|
830
935
|
}
|
|
831
936
|
|
|
937
|
+
// Handle exit/quit without slash
|
|
832
938
|
if (input.toLowerCase() === 'exit' || input.toLowerCase() === 'quit') {
|
|
833
939
|
console.log('Goodbye!');
|
|
834
940
|
rl.close();
|
|
835
941
|
return;
|
|
836
942
|
}
|
|
837
943
|
|
|
838
|
-
|
|
944
|
+
// Build message list based on history retention setting
|
|
945
|
+
const currentMessages = settings.retainHistory ? [...history.messages] : [];
|
|
839
946
|
currentMessages.push({ role: 'user', content: input });
|
|
840
947
|
|
|
841
|
-
|
|
842
|
-
|
|
948
|
+
// Send message
|
|
949
|
+
let response;
|
|
950
|
+
if (settings.stream) {
|
|
951
|
+
response = await streamResponse(currentMessages);
|
|
952
|
+
} else {
|
|
953
|
+
response = await nonStreamResponse(currentMessages);
|
|
843
954
|
}
|
|
844
955
|
|
|
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();
|
|
956
|
+
// Save to history
|
|
957
|
+
if (settings.retainHistory && response) {
|
|
958
|
+
history.messages.push({ role: 'user', content: input });
|
|
959
|
+
history.messages.push({ role: 'assistant', content: response });
|
|
960
|
+
saveHistory(history);
|
|
890
961
|
}
|
|
962
|
+
|
|
963
|
+
chat();
|
|
891
964
|
});
|
|
892
965
|
}
|
|
893
966
|
|
|
894
|
-
//
|
|
967
|
+
// Show initial settings and start chat
|
|
895
968
|
console.log('Type "/help" for commands, "/auth" for auth menu, or "/exit" to quit.\n');
|
|
896
969
|
showSettings();
|
|
897
970
|
chat();
|
|
898
971
|
|
|
899
972
|
} catch (error) {
|
|
900
|
-
console.error('Error
|
|
973
|
+
console.error('Error:', error.message);
|
|
901
974
|
process.exit(1);
|
|
902
975
|
}
|
|
903
976
|
}
|