Skip to content
This repository was archived by the owner on Jul 4, 2025. It is now read-only.

Commit f0e9a7a

Browse files
authored
chore: cortex chat enhancement (#631)
1 parent dd551e0 commit f0e9a7a

File tree

4 files changed

+101
-53
lines changed

4 files changed

+101
-53
lines changed

cortex-js/src/infrastructure/commanders/chat.command.ts

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
import { CommandRunner, SubCommand, Option } from 'nest-commander';
1+
import {
2+
CommandRunner,
3+
SubCommand,
4+
Option,
5+
InquirerService,
6+
} from 'nest-commander';
27
import { ChatCliUsecases } from './usecases/chat.cli.usecases';
38
import { exit } from 'node:process';
9+
import { PSCliUsecases } from './usecases/ps.cli.usecases';
10+
import { ModelsUsecases } from '@/usecases/models/models.usecases';
411

512
type ChatOptions = {
613
threadId?: string;
@@ -10,22 +17,52 @@ type ChatOptions = {
1017

1118
@SubCommand({ name: 'chat', description: 'Send a chat request to a model' })
1219
export class ChatCommand extends CommandRunner {
13-
constructor(private readonly chatCliUsecases: ChatCliUsecases) {
20+
constructor(
21+
private readonly inquirerService: InquirerService,
22+
private readonly chatCliUsecases: ChatCliUsecases,
23+
private readonly modelsUsecases: ModelsUsecases,
24+
private readonly psCliUsecases: PSCliUsecases,
25+
) {
1426
super();
1527
}
1628

1729
async run(_input: string[], options: ChatOptions): Promise<void> {
18-
const modelId = _input[0];
19-
if (!modelId) {
20-
console.error('Model ID is required');
21-
exit(1);
30+
let modelId = _input[0];
31+
// First attempt to get message from input or options
32+
let message = _input[1] ?? options.message;
33+
34+
// Check for model existing
35+
if (!modelId || !(await this.modelsUsecases.findOne(modelId))) {
36+
// Model ID is not provided
37+
// first input might be message input
38+
message = _input[0] ?? options.message;
39+
// If model ID is not provided, prompt user to select from running models
40+
const models = await this.psCliUsecases.getModels();
41+
if (models.length === 1) {
42+
modelId = models[0].modelId;
43+
} else if (models.length > 0) {
44+
const { model } = await this.inquirerService.inquirer.prompt({
45+
type: 'list',
46+
name: 'model',
47+
message: 'Select running model to chat with:',
48+
choices: models.map((e) => ({
49+
name: e.modelId,
50+
value: e.modelId,
51+
})),
52+
});
53+
modelId = model;
54+
} else {
55+
console.error('Model ID is required');
56+
exit(1);
57+
}
2258
}
2359

2460
return this.chatCliUsecases.chat(
2561
modelId,
2662
options.threadId,
27-
options.message,
63+
message, // Accept both message from inputs or arguments
2864
options.attach,
65+
false, // Do not stop cortex session or loaded model
2966
);
3067
}
3168

@@ -40,7 +77,6 @@ export class ChatCommand extends CommandRunner {
4077
@Option({
4178
flags: '-m, --message <message>',
4279
description: 'Message to send to the model',
43-
required: true,
4480
})
4581
parseModelId(value: string) {
4682
return value;
Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
1-
import { CommandRunner, SubCommand } from 'nest-commander';
1+
import { CommandRunner, SubCommand, Option } from 'nest-commander';
22
import { ModelsCliUsecases } from '../usecases/models.cli.usecases';
33

4+
interface ModelListOptions {
5+
format: 'table' | 'json';
6+
}
47
@SubCommand({ name: 'list', description: 'List all models locally.' })
58
export class ModelListCommand extends CommandRunner {
69
constructor(private readonly modelsCliUsecases: ModelsCliUsecases) {
710
super();
811
}
912

10-
async run(): Promise<void> {
13+
async run(_input: string[], option: ModelListOptions): Promise<void> {
1114
const models = await this.modelsCliUsecases.listAllModels();
12-
console.log(models);
15+
option.format === 'table' ? console.table(models) : console.log(models);
16+
}
17+
18+
@Option({
19+
flags: '-f, --format <format>',
20+
defaultValue: 'json',
21+
description: 'Print models list in table or json format',
22+
})
23+
parseModelId(value: string) {
24+
return value;
1325
}
1426
}

cortex-js/src/infrastructure/commanders/models/model-stop.command.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export class ModelStopCommand extends CommandRunner {
2020

2121
await this.modelsCliUsecases
2222
.stopModel(input[0])
23-
.then(() => this.cortexUsecases.stopCortex())
23+
.then(() => this.modelsCliUsecases.stopModel(input[0]))
2424
.then(console.log);
2525
}
2626
}

cortex-js/src/infrastructure/commanders/usecases/chat.cli.usecases.ts

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -36,47 +36,12 @@ export class ChatCliUsecases {
3636
private readonly messagesUsecases: MessagesUsecases,
3737
) {}
3838

39-
private async getOrCreateNewThread(
40-
modelId: string,
41-
threadId?: string,
42-
): Promise<Thread> {
43-
if (threadId) {
44-
const thread = await this.threadUsecases.findOne(threadId);
45-
if (!thread) throw new Error(`Cannot find thread with id: ${threadId}`);
46-
return thread;
47-
}
48-
49-
const model = await this.modelsUsecases.findOne(modelId);
50-
if (!model) throw new Error(`Cannot find model with id: ${modelId}`);
51-
52-
const assistant = await this.assistantUsecases.findOne('jan');
53-
if (!assistant) throw new Error('No assistant available');
54-
55-
const createThreadModel: CreateThreadModelInfoDto = {
56-
id: modelId,
57-
settings: model.settings,
58-
parameters: model.parameters,
59-
};
60-
61-
const assistantDto: CreateThreadAssistantDto = {
62-
assistant_id: assistant.id,
63-
assistant_name: assistant.name,
64-
model: createThreadModel,
65-
};
66-
67-
const createThreadDto: CreateThreadDto = {
68-
title: 'New Thread',
69-
assistants: [assistantDto],
70-
};
71-
72-
return this.threadUsecases.create(createThreadDto);
73-
}
74-
7539
async chat(
7640
modelId: string,
7741
threadId?: string,
7842
message?: string,
7943
attach: boolean = true,
44+
stopModel: boolean = true,
8045
): Promise<void> {
8146
if (attach) console.log(`Inorder to exit, type '${this.exitClause}'.`);
8247
const thread = await this.getOrCreateNewThread(modelId, threadId);
@@ -95,11 +60,10 @@ export class ChatCliUsecases {
9560
if (message) sendCompletionMessage.bind(this)(message);
9661
if (attach) rl.prompt();
9762

98-
rl.on('close', () => {
99-
this.cortexUsecases.stopCortex().then(() => {
100-
if (attach) console.log(this.exitMessage);
101-
exit(0);
102-
});
63+
rl.on('close', async () => {
64+
if (stopModel) await this.modelsUsecases.stopModel(modelId);
65+
if (attach) console.log(this.exitMessage);
66+
exit(0);
10367
});
10468

10569
rl.on('line', sendCompletionMessage.bind(this));
@@ -213,4 +177,40 @@ export class ChatCliUsecases {
213177
});
214178
}
215179
}
180+
181+
private async getOrCreateNewThread(
182+
modelId: string,
183+
threadId?: string,
184+
): Promise<Thread> {
185+
if (threadId) {
186+
const thread = await this.threadUsecases.findOne(threadId);
187+
if (!thread) throw new Error(`Cannot find thread with id: ${threadId}`);
188+
return thread;
189+
}
190+
191+
const model = await this.modelsUsecases.findOne(modelId);
192+
if (!model) throw new Error(`Cannot find model with id: ${modelId}`);
193+
194+
const assistant = await this.assistantUsecases.findOne('jan');
195+
if (!assistant) throw new Error('No assistant available');
196+
197+
const createThreadModel: CreateThreadModelInfoDto = {
198+
id: modelId,
199+
settings: model.settings,
200+
parameters: model.parameters,
201+
};
202+
203+
const assistantDto: CreateThreadAssistantDto = {
204+
assistant_id: assistant.id,
205+
assistant_name: assistant.name,
206+
model: createThreadModel,
207+
};
208+
209+
const createThreadDto: CreateThreadDto = {
210+
title: 'New Thread',
211+
assistants: [assistantDto],
212+
};
213+
214+
return this.threadUsecases.create(createThreadDto);
215+
}
216216
}

0 commit comments

Comments
 (0)