family-ai-agent 1.0.2 ā 1.0.3
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/dist/cli/commands/config.d.ts +7 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +300 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/index.js +113 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/setup-wizard.d.ts +19 -0
- package/dist/cli/setup-wizard.d.ts.map +1 -0
- package/dist/cli/setup-wizard.js +294 -0
- package/dist/cli/setup-wizard.js.map +1 -0
- package/dist/config/index.d.ts +6 -3
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +114 -5
- package/dist/config/index.js.map +1 -1
- package/dist/config/user-config.d.ts +203 -0
- package/dist/config/user-config.d.ts.map +1 -0
- package/dist/config/user-config.js +267 -0
- package/dist/config/user-config.js.map +1 -0
- package/package.json +1 -1
- package/src/cli/commands/config.ts +358 -0
- package/src/cli/index.ts +127 -17
- package/src/cli/setup-wizard.ts +343 -0
- package/src/config/index.ts +164 -5
- package/src/config/user-config.ts +323 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
loadUserConfig,
|
|
8
|
+
saveUserConfig,
|
|
9
|
+
deleteUserConfig,
|
|
10
|
+
updateUserConfig,
|
|
11
|
+
addCustomModel,
|
|
12
|
+
removeCustomModel,
|
|
13
|
+
getAllModels,
|
|
14
|
+
getDisplayConfig,
|
|
15
|
+
getConfigPath,
|
|
16
|
+
configExists,
|
|
17
|
+
type CustomModel,
|
|
18
|
+
} from '../../config/user-config.js';
|
|
19
|
+
import { runSetupWizard } from '../setup-wizard.js';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Create config command group
|
|
23
|
+
*/
|
|
24
|
+
export function createConfigCommand(): Command {
|
|
25
|
+
const configCmd = new Command('config')
|
|
26
|
+
.description('Manage Family AI Agent configuration');
|
|
27
|
+
|
|
28
|
+
// config setup - Run interactive setup wizard
|
|
29
|
+
configCmd
|
|
30
|
+
.command('setup')
|
|
31
|
+
.description('Run interactive setup wizard')
|
|
32
|
+
.action(async () => {
|
|
33
|
+
await runSetupWizard();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// config show - Display current configuration
|
|
37
|
+
configCmd
|
|
38
|
+
.command('show')
|
|
39
|
+
.description('Display current configuration')
|
|
40
|
+
.action(() => {
|
|
41
|
+
const config = getDisplayConfig();
|
|
42
|
+
|
|
43
|
+
if (!config) {
|
|
44
|
+
console.log(chalk.yellow('\nNo configuration found.'));
|
|
45
|
+
console.log(chalk.gray('Run `family-ai-agent config setup` to create one.\n'));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log(chalk.bold('\nš Current Configuration\n'));
|
|
50
|
+
console.log(chalk.white('Location: ') + chalk.gray(getConfigPath()));
|
|
51
|
+
console.log();
|
|
52
|
+
|
|
53
|
+
// API Settings
|
|
54
|
+
console.log(chalk.bold.cyan('API Settings'));
|
|
55
|
+
console.log(` API Key: ${chalk.gray(config.apiKey as string)}`);
|
|
56
|
+
console.log(` Base URL: ${chalk.gray(config.baseUrl as string)}`);
|
|
57
|
+
console.log();
|
|
58
|
+
|
|
59
|
+
// Model Settings
|
|
60
|
+
console.log(chalk.bold.cyan('Models'));
|
|
61
|
+
console.log(` Default: ${chalk.green(config.defaultModel as string)}`);
|
|
62
|
+
console.log(` Fast: ${chalk.green(config.fastModel as string)}`);
|
|
63
|
+
console.log(` Embedding: ${chalk.green(config.embeddingModel as string)}`);
|
|
64
|
+
console.log();
|
|
65
|
+
|
|
66
|
+
// Safety Settings
|
|
67
|
+
console.log(chalk.bold.cyan('Safety'));
|
|
68
|
+
console.log(
|
|
69
|
+
` Filters: ${(config.enableSafetyFilters as boolean) ? chalk.green('Enabled') : chalk.yellow('Disabled')}`
|
|
70
|
+
);
|
|
71
|
+
console.log(
|
|
72
|
+
` Logging: ${(config.enableAuditLogging as boolean) ? chalk.green('Enabled') : chalk.yellow('Disabled')}`
|
|
73
|
+
);
|
|
74
|
+
console.log();
|
|
75
|
+
|
|
76
|
+
// Custom Models
|
|
77
|
+
const customModels = config.customModels as CustomModel[];
|
|
78
|
+
if (customModels && customModels.length > 0) {
|
|
79
|
+
console.log(chalk.bold.cyan('Custom Models'));
|
|
80
|
+
for (const model of customModels) {
|
|
81
|
+
console.log(` - ${chalk.white(model.name)} (${chalk.gray(model.id)})`);
|
|
82
|
+
}
|
|
83
|
+
console.log();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Timestamps
|
|
87
|
+
if (config.createdAt || config.updatedAt) {
|
|
88
|
+
console.log(chalk.bold.cyan('Metadata'));
|
|
89
|
+
if (config.createdAt) {
|
|
90
|
+
console.log(` Created: ${chalk.gray(new Date(config.createdAt as string).toLocaleString())}`);
|
|
91
|
+
}
|
|
92
|
+
if (config.updatedAt) {
|
|
93
|
+
console.log(` Updated: ${chalk.gray(new Date(config.updatedAt as string).toLocaleString())}`);
|
|
94
|
+
}
|
|
95
|
+
console.log();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// config set <key> <value> - Set a configuration value
|
|
100
|
+
configCmd
|
|
101
|
+
.command('set <key> <value>')
|
|
102
|
+
.description('Set a configuration value')
|
|
103
|
+
.action(async (key: string, value: string) => {
|
|
104
|
+
if (!configExists()) {
|
|
105
|
+
console.log(chalk.yellow('\nNo configuration found.'));
|
|
106
|
+
console.log(chalk.gray('Run `family-ai-agent config setup` first.\n'));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const validKeys = [
|
|
111
|
+
'apiKey',
|
|
112
|
+
'baseUrl',
|
|
113
|
+
'defaultModel',
|
|
114
|
+
'fastModel',
|
|
115
|
+
'embeddingModel',
|
|
116
|
+
'enableSafetyFilters',
|
|
117
|
+
'enableAuditLogging',
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
// Map common aliases
|
|
121
|
+
const keyAliases: Record<string, string> = {
|
|
122
|
+
'api-key': 'apiKey',
|
|
123
|
+
'api_key': 'apiKey',
|
|
124
|
+
'key': 'apiKey',
|
|
125
|
+
'base-url': 'baseUrl',
|
|
126
|
+
'base_url': 'baseUrl',
|
|
127
|
+
'url': 'baseUrl',
|
|
128
|
+
'model': 'defaultModel',
|
|
129
|
+
'default-model': 'defaultModel',
|
|
130
|
+
'default_model': 'defaultModel',
|
|
131
|
+
'fast-model': 'fastModel',
|
|
132
|
+
'fast_model': 'fastModel',
|
|
133
|
+
'fast': 'fastModel',
|
|
134
|
+
'embedding': 'embeddingModel',
|
|
135
|
+
'embedding-model': 'embeddingModel',
|
|
136
|
+
'safety': 'enableSafetyFilters',
|
|
137
|
+
'filters': 'enableSafetyFilters',
|
|
138
|
+
'logging': 'enableAuditLogging',
|
|
139
|
+
'audit': 'enableAuditLogging',
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const normalizedKey = keyAliases[key.toLowerCase()] || key;
|
|
143
|
+
|
|
144
|
+
if (!validKeys.includes(normalizedKey)) {
|
|
145
|
+
console.log(chalk.red(`\nUnknown configuration key: ${key}`));
|
|
146
|
+
console.log(chalk.gray(`Valid keys: ${validKeys.join(', ')}\n`));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const spinner = ora('Updating configuration...').start();
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
// Handle boolean values
|
|
154
|
+
let parsedValue: unknown = value;
|
|
155
|
+
if (normalizedKey.startsWith('enable')) {
|
|
156
|
+
parsedValue = ['true', '1', 'yes', 'on'].includes(value.toLowerCase());
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
updateUserConfig({ [normalizedKey]: parsedValue });
|
|
160
|
+
spinner.succeed(`Set ${normalizedKey} = ${value}`);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
spinner.fail('Failed to update configuration');
|
|
163
|
+
console.error(chalk.red(error instanceof Error ? error.message : 'Unknown error'));
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// config models - List available models
|
|
168
|
+
configCmd
|
|
169
|
+
.command('models')
|
|
170
|
+
.description('List available models')
|
|
171
|
+
.action(() => {
|
|
172
|
+
const models = getAllModels();
|
|
173
|
+
|
|
174
|
+
console.log(chalk.bold('\nš¦ Available Models\n'));
|
|
175
|
+
|
|
176
|
+
// Group by type
|
|
177
|
+
const builtIn = models.filter((m) => !m.isCustom);
|
|
178
|
+
const custom = models.filter((m) => m.isCustom);
|
|
179
|
+
|
|
180
|
+
console.log(chalk.bold.cyan('Built-in Models'));
|
|
181
|
+
for (const model of builtIn) {
|
|
182
|
+
console.log(` ${chalk.white(model.name)}`);
|
|
183
|
+
console.log(` ${chalk.gray(model.id)}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (custom.length > 0) {
|
|
187
|
+
console.log();
|
|
188
|
+
console.log(chalk.bold.cyan('Custom Models'));
|
|
189
|
+
for (const model of custom) {
|
|
190
|
+
console.log(` ${chalk.white(model.name)}`);
|
|
191
|
+
console.log(` ${chalk.gray(model.id)}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
console.log();
|
|
196
|
+
console.log(chalk.gray('Tip: Use `config add-model` to add a custom model.'));
|
|
197
|
+
console.log();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// config add-model - Add a custom model
|
|
201
|
+
configCmd
|
|
202
|
+
.command('add-model')
|
|
203
|
+
.description('Add a custom model')
|
|
204
|
+
.action(async () => {
|
|
205
|
+
if (!configExists()) {
|
|
206
|
+
console.log(chalk.yellow('\nNo configuration found.'));
|
|
207
|
+
console.log(chalk.gray('Run `family-ai-agent config setup` first.\n'));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
console.log(chalk.bold('\nā Add Custom Model\n'));
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
const answers = await inquirer.prompt<{
|
|
215
|
+
id: string;
|
|
216
|
+
name: string;
|
|
217
|
+
contextWindow: number;
|
|
218
|
+
maxOutput: number;
|
|
219
|
+
description: string;
|
|
220
|
+
}>([
|
|
221
|
+
{
|
|
222
|
+
type: 'input',
|
|
223
|
+
name: 'id',
|
|
224
|
+
message: 'Model ID (e.g., provider/model-name):',
|
|
225
|
+
validate: (input: string) => {
|
|
226
|
+
if (!input || input.trim().length === 0) {
|
|
227
|
+
return 'Model ID is required';
|
|
228
|
+
}
|
|
229
|
+
return true;
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
type: 'input',
|
|
234
|
+
name: 'name',
|
|
235
|
+
message: 'Display name:',
|
|
236
|
+
validate: (input: string) => {
|
|
237
|
+
if (!input || input.trim().length === 0) {
|
|
238
|
+
return 'Display name is required';
|
|
239
|
+
}
|
|
240
|
+
return true;
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
type: 'number',
|
|
245
|
+
name: 'contextWindow',
|
|
246
|
+
message: 'Context window size:',
|
|
247
|
+
default: 8192,
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
type: 'number',
|
|
251
|
+
name: 'maxOutput',
|
|
252
|
+
message: 'Max output tokens:',
|
|
253
|
+
default: 4096,
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
type: 'input',
|
|
257
|
+
name: 'description',
|
|
258
|
+
message: 'Description (optional):',
|
|
259
|
+
default: '',
|
|
260
|
+
},
|
|
261
|
+
]);
|
|
262
|
+
|
|
263
|
+
const model: CustomModel = {
|
|
264
|
+
id: answers.id,
|
|
265
|
+
name: answers.name,
|
|
266
|
+
contextWindow: answers.contextWindow,
|
|
267
|
+
maxOutput: answers.maxOutput,
|
|
268
|
+
description: answers.description || undefined,
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
addCustomModel(model);
|
|
272
|
+
console.log(chalk.green(`\nā Added custom model: ${model.name}\n`));
|
|
273
|
+
} catch (error) {
|
|
274
|
+
if ((error as { name?: string }).name === 'ExitPromptError') {
|
|
275
|
+
console.log(chalk.yellow('\nCancelled.\n'));
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// config remove-model <id> - Remove a custom model
|
|
283
|
+
configCmd
|
|
284
|
+
.command('remove-model <id>')
|
|
285
|
+
.description('Remove a custom model')
|
|
286
|
+
.action(async (id: string) => {
|
|
287
|
+
if (!configExists()) {
|
|
288
|
+
console.log(chalk.yellow('\nNo configuration found.\n'));
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const config = loadUserConfig();
|
|
293
|
+
const model = config?.customModels.find((m) => m.id === id);
|
|
294
|
+
|
|
295
|
+
if (!model) {
|
|
296
|
+
console.log(chalk.yellow(`\nModel not found: ${id}\n`));
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const { confirm } = await inquirer.prompt<{ confirm: boolean }>([
|
|
301
|
+
{
|
|
302
|
+
type: 'confirm',
|
|
303
|
+
name: 'confirm',
|
|
304
|
+
message: `Remove custom model "${model.name}"?`,
|
|
305
|
+
default: false,
|
|
306
|
+
},
|
|
307
|
+
]);
|
|
308
|
+
|
|
309
|
+
if (confirm) {
|
|
310
|
+
removeCustomModel(id);
|
|
311
|
+
console.log(chalk.green(`\nā Removed model: ${model.name}\n`));
|
|
312
|
+
} else {
|
|
313
|
+
console.log(chalk.gray('\nCancelled.\n'));
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// config reset - Reset configuration
|
|
318
|
+
configCmd
|
|
319
|
+
.command('reset')
|
|
320
|
+
.description('Reset configuration to defaults')
|
|
321
|
+
.action(async () => {
|
|
322
|
+
if (!configExists()) {
|
|
323
|
+
console.log(chalk.yellow('\nNo configuration to reset.\n'));
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const { confirm } = await inquirer.prompt<{ confirm: boolean }>([
|
|
328
|
+
{
|
|
329
|
+
type: 'confirm',
|
|
330
|
+
name: 'confirm',
|
|
331
|
+
message: chalk.red('Are you sure you want to reset all configuration?'),
|
|
332
|
+
default: false,
|
|
333
|
+
},
|
|
334
|
+
]);
|
|
335
|
+
|
|
336
|
+
if (confirm) {
|
|
337
|
+
deleteUserConfig();
|
|
338
|
+
console.log(chalk.green('\nā Configuration reset.\n'));
|
|
339
|
+
console.log(chalk.gray('Run `family-ai-agent config setup` to reconfigure.\n'));
|
|
340
|
+
} else {
|
|
341
|
+
console.log(chalk.gray('\nCancelled.\n'));
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
// config path - Show config file path
|
|
346
|
+
configCmd
|
|
347
|
+
.command('path')
|
|
348
|
+
.description('Show configuration file path')
|
|
349
|
+
.action(() => {
|
|
350
|
+
console.log(chalk.white('\nConfiguration file:'));
|
|
351
|
+
console.log(chalk.cyan(getConfigPath()));
|
|
352
|
+
console.log();
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
return configCmd;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export default createConfigCommand;
|
package/src/cli/index.ts
CHANGED
|
@@ -6,17 +6,20 @@ import chalk from 'chalk';
|
|
|
6
6
|
import ora from 'ora';
|
|
7
7
|
import boxen from 'boxen';
|
|
8
8
|
|
|
9
|
-
import { runOrchestrator
|
|
9
|
+
import { runOrchestrator } from '../core/orchestrator/graph.js';
|
|
10
10
|
import { getVectorStore } from '../memory/longterm/vector-store.js';
|
|
11
11
|
import { getConversationMemory } from '../memory/conversation/index.js';
|
|
12
12
|
import { getKnowledgeBase } from '../memory/knowledge-base/index.js';
|
|
13
13
|
import { validateInput } from '../safety/guardrails/input-guardrail.js';
|
|
14
14
|
import { validateOutput } from '../safety/guardrails/output-guardrail.js';
|
|
15
15
|
import { initDatabase, closePool } from '../database/client.js';
|
|
16
|
-
import { config,
|
|
16
|
+
import { config, isConfigured, hasUserConfig, getUserConfigPath } from '../config/index.js';
|
|
17
17
|
import { createLogger } from '../utils/logger.js';
|
|
18
18
|
import { nanoid } from 'nanoid';
|
|
19
19
|
|
|
20
|
+
import { runSetupWizard, checkAndRunSetup } from './setup-wizard.js';
|
|
21
|
+
import { createConfigCommand } from './commands/config.js';
|
|
22
|
+
|
|
20
23
|
const logger = createLogger('CLI');
|
|
21
24
|
const program = new Command();
|
|
22
25
|
|
|
@@ -38,15 +41,80 @@ function showBanner(): void {
|
|
|
38
41
|
console.log(banner);
|
|
39
42
|
}
|
|
40
43
|
|
|
44
|
+
// Check if configured and prompt setup if needed
|
|
45
|
+
async function ensureConfigured(): Promise<boolean> {
|
|
46
|
+
if (isConfigured()) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log(chalk.yellow('\nā ļø No API key configured.\n'));
|
|
51
|
+
|
|
52
|
+
const { action } = await inquirer.prompt<{ action: string }>([
|
|
53
|
+
{
|
|
54
|
+
type: 'list',
|
|
55
|
+
name: 'action',
|
|
56
|
+
message: 'What would you like to do?',
|
|
57
|
+
choices: [
|
|
58
|
+
{ name: 'Run setup wizard', value: 'setup' },
|
|
59
|
+
{ name: 'Enter API key directly', value: 'quick' },
|
|
60
|
+
{ name: 'Exit', value: 'exit' },
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
if (action === 'exit') {
|
|
66
|
+
console.log(chalk.gray('\nRun `family-ai-agent config setup` when ready.\n'));
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (action === 'quick') {
|
|
71
|
+
const { apiKey } = await inquirer.prompt<{ apiKey: string }>([
|
|
72
|
+
{
|
|
73
|
+
type: 'password',
|
|
74
|
+
name: 'apiKey',
|
|
75
|
+
message: 'Enter your OpenRouter API Key:',
|
|
76
|
+
mask: '*',
|
|
77
|
+
validate: (input: string) => {
|
|
78
|
+
if (!input || input.trim().length === 0) {
|
|
79
|
+
return 'API key is required';
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
const { runQuickSetup } = await import('./setup-wizard.js');
|
|
87
|
+
const success = await runQuickSetup(apiKey);
|
|
88
|
+
|
|
89
|
+
if (success) {
|
|
90
|
+
console.log(chalk.green('\nā Configuration saved! Please restart the application.\n'));
|
|
91
|
+
}
|
|
92
|
+
return false; // Need restart to pick up new config
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Full setup wizard
|
|
96
|
+
const success = await runSetupWizard();
|
|
97
|
+
if (success) {
|
|
98
|
+
console.log(chalk.gray('\nPlease restart the application to apply the new configuration.\n'));
|
|
99
|
+
}
|
|
100
|
+
return false; // Need restart to pick up new config
|
|
101
|
+
}
|
|
102
|
+
|
|
41
103
|
// Interactive chat mode
|
|
42
104
|
async function startInteractiveChat(): Promise<void> {
|
|
43
105
|
showBanner();
|
|
44
106
|
|
|
107
|
+
// Show config status
|
|
108
|
+
if (hasUserConfig()) {
|
|
109
|
+
console.log(chalk.gray(`\nConfig: ${getUserConfigPath()}`));
|
|
110
|
+
}
|
|
111
|
+
console.log(chalk.gray(`Model: ${config.DEFAULT_MODEL}`));
|
|
112
|
+
|
|
45
113
|
const threadId = `thread-${nanoid(8)}`;
|
|
46
114
|
const conversationMemory = getConversationMemory();
|
|
47
115
|
const vectorStore = getVectorStore();
|
|
48
116
|
|
|
49
|
-
console.log(chalk.gray(
|
|
117
|
+
console.log(chalk.gray(`Session: ${threadId}`));
|
|
50
118
|
console.log(chalk.gray('Type "exit" or "quit" to end the session'));
|
|
51
119
|
console.log(chalk.gray('Type "clear" to start a new conversation'));
|
|
52
120
|
console.log(chalk.gray('Type "memory" to view recent memories'));
|
|
@@ -250,15 +318,21 @@ async function runQuery(query: string): Promise<void> {
|
|
|
250
318
|
|
|
251
319
|
// Main program setup
|
|
252
320
|
program
|
|
253
|
-
.name('family-ai')
|
|
321
|
+
.name('family-ai-agent')
|
|
254
322
|
.description('Family AI Agent - Your AI Family for All Tasks')
|
|
255
|
-
.version('1.0.
|
|
323
|
+
.version('1.0.2');
|
|
324
|
+
|
|
325
|
+
// Add config command group
|
|
326
|
+
program.addCommand(createConfigCommand());
|
|
256
327
|
|
|
257
328
|
program
|
|
258
329
|
.command('chat')
|
|
259
330
|
.description('Start interactive chat mode')
|
|
260
331
|
.action(async () => {
|
|
261
332
|
try {
|
|
333
|
+
if (!(await ensureConfigured())) {
|
|
334
|
+
process.exit(0);
|
|
335
|
+
}
|
|
262
336
|
await initDatabase();
|
|
263
337
|
await startInteractiveChat();
|
|
264
338
|
} catch (error) {
|
|
@@ -274,6 +348,9 @@ program
|
|
|
274
348
|
.description('Ask a single question')
|
|
275
349
|
.action(async (query: string) => {
|
|
276
350
|
try {
|
|
351
|
+
if (!(await ensureConfigured())) {
|
|
352
|
+
process.exit(0);
|
|
353
|
+
}
|
|
277
354
|
await initDatabase();
|
|
278
355
|
await runQuery(query);
|
|
279
356
|
} catch (error) {
|
|
@@ -288,6 +365,10 @@ program
|
|
|
288
365
|
.command('upload <filepath>')
|
|
289
366
|
.description('Upload a document to the knowledge base')
|
|
290
367
|
.action(async (filepath: string) => {
|
|
368
|
+
if (!(await ensureConfigured())) {
|
|
369
|
+
process.exit(0);
|
|
370
|
+
}
|
|
371
|
+
|
|
291
372
|
const spinner = ora('Uploading document...').start();
|
|
292
373
|
|
|
293
374
|
try {
|
|
@@ -321,6 +402,10 @@ program
|
|
|
321
402
|
.description('Search the knowledge base')
|
|
322
403
|
.option('-l, --limit <number>', 'Maximum results', '5')
|
|
323
404
|
.action(async (query: string, options: { limit: string }) => {
|
|
405
|
+
if (!(await ensureConfigured())) {
|
|
406
|
+
process.exit(0);
|
|
407
|
+
}
|
|
408
|
+
|
|
324
409
|
const spinner = ora('Searching...').start();
|
|
325
410
|
|
|
326
411
|
try {
|
|
@@ -357,22 +442,36 @@ program
|
|
|
357
442
|
.command('status')
|
|
358
443
|
.description('Show system status')
|
|
359
444
|
.action(async () => {
|
|
445
|
+
console.log(chalk.bold('\nš¤ Family AI Agent Status\n'));
|
|
446
|
+
|
|
447
|
+
// Config status
|
|
448
|
+
if (hasUserConfig()) {
|
|
449
|
+
console.log(chalk.white('Config:'), chalk.green('User config loaded'));
|
|
450
|
+
console.log(chalk.gray(` ${getUserConfigPath()}`));
|
|
451
|
+
} else if (isConfigured()) {
|
|
452
|
+
console.log(chalk.white('Config:'), chalk.yellow('Using environment variables'));
|
|
453
|
+
} else {
|
|
454
|
+
console.log(chalk.white('Config:'), chalk.red('Not configured'));
|
|
455
|
+
console.log(chalk.gray(' Run `family-ai-agent config setup` to configure'));
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
console.log(chalk.white('API Key:'), isConfigured() ? chalk.green('Set') : chalk.red('Missing'));
|
|
459
|
+
console.log(chalk.white('Default Model:'), chalk.cyan(config.DEFAULT_MODEL));
|
|
460
|
+
console.log(chalk.white('Fast Model:'), chalk.cyan(config.FAST_MODEL));
|
|
461
|
+
console.log(chalk.white('Safety Filters:'), config.ENABLE_CONTENT_FILTER ? chalk.green('Enabled') : chalk.yellow('Disabled'));
|
|
462
|
+
console.log(chalk.white('Audit Logging:'), config.ENABLE_AUDIT_LOGGING ? chalk.green('Enabled') : chalk.yellow('Disabled'));
|
|
463
|
+
|
|
464
|
+
// Database status
|
|
360
465
|
try {
|
|
361
466
|
await initDatabase();
|
|
362
|
-
|
|
363
|
-
console.log(chalk.bold('\nš¤ Family AI Agent Status\n'));
|
|
364
467
|
console.log(chalk.white('Database:'), chalk.green('Connected'));
|
|
365
|
-
|
|
366
|
-
console.log(chalk.white('Default Model:'), chalk.cyan(config.DEFAULT_MODEL));
|
|
367
|
-
console.log(chalk.white('Safety Filters:'), config.ENABLE_CONTENT_FILTER ? chalk.green('Enabled') : chalk.yellow('Disabled'));
|
|
368
|
-
console.log(chalk.white('Audit Logging:'), config.ENABLE_AUDIT_LOGGING ? chalk.green('Enabled') : chalk.yellow('Disabled'));
|
|
369
|
-
console.log();
|
|
370
|
-
} catch (error) {
|
|
468
|
+
} catch {
|
|
371
469
|
console.log(chalk.white('Database:'), chalk.red('Disconnected'));
|
|
372
|
-
console.error(error instanceof Error ? error.message : 'Unknown error');
|
|
373
470
|
} finally {
|
|
374
471
|
await closePool();
|
|
375
472
|
}
|
|
473
|
+
|
|
474
|
+
console.log();
|
|
376
475
|
});
|
|
377
476
|
|
|
378
477
|
// Handle unhandled rejections
|
|
@@ -386,7 +485,18 @@ program.parse();
|
|
|
386
485
|
|
|
387
486
|
// If no command specified, start interactive chat
|
|
388
487
|
if (!process.argv.slice(2).length) {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
488
|
+
(async () => {
|
|
489
|
+
try {
|
|
490
|
+
if (!(await ensureConfigured())) {
|
|
491
|
+
process.exit(0);
|
|
492
|
+
}
|
|
493
|
+
await initDatabase();
|
|
494
|
+
await startInteractiveChat();
|
|
495
|
+
} catch (error) {
|
|
496
|
+
console.error(chalk.red('Failed to start:'), error);
|
|
497
|
+
process.exit(1);
|
|
498
|
+
} finally {
|
|
499
|
+
await closePool();
|
|
500
|
+
}
|
|
501
|
+
})();
|
|
392
502
|
}
|