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

Commit 862ccba

Browse files
committed
Merge branch 'dev' of https://github.com/janhq/cortex into readme
2 parents 8c51521 + c08c797 commit 862ccba

File tree

12 files changed

+116
-128
lines changed

12 files changed

+116
-128
lines changed

cortex-js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
"@types/js-yaml": "^4.0.9",
7272
"@types/node": "^20.12.9",
7373
"@types/supertest": "^6.0.2",
74-
"@types/update-notifier": "^5.0.8",
74+
"@types/update-notifier": "^6.0.8",
7575
"@types/uuid": "^9.0.8",
7676
"@typescript-eslint/eslint-plugin": "^6.0.0",
7777
"@typescript-eslint/parser": "^6.0.0",

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-pull.command.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export class ModelPullCommand extends CommandRunner {
5050
name: sanitizedInput,
5151
};
5252

53+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
5354
for await (const _fileInfo of listFiles({ repo })) {
5455
break;
5556
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ export class ModelRemoveCommand extends CommandRunner {
1414
exit(1);
1515
}
1616

17-
const result = await this.modelsCliUsecases.removeModel(input[0]);
18-
console.log(result);
17+
await this.modelsCliUsecases.removeModel(input[0]).then(console.log);
1918
}
2019
}
Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
import { CommandRunner, SubCommand } from 'nest-commander';
22
import { exit } from 'node:process';
33
import { ModelsCliUsecases } from '../usecases/models.cli.usecases';
4-
import { CortexUsecases } from '@/usecases/cortex/cortex.usecases';
54

65
@SubCommand({ name: 'stop', description: 'Stop a model by ID.' })
76
export class ModelStopCommand extends CommandRunner {
8-
constructor(
9-
private readonly cortexUsecases: CortexUsecases,
10-
private readonly modelsCliUsecases: ModelsCliUsecases,
11-
) {
7+
constructor(private readonly modelsCliUsecases: ModelsCliUsecases) {
128
super();
139
}
1410

@@ -20,7 +16,7 @@ export class ModelStopCommand extends CommandRunner {
2016

2117
await this.modelsCliUsecases
2218
.stopModel(input[0])
23-
.then(() => this.cortexUsecases.stopCortex())
19+
.then(() => this.modelsCliUsecases.stopModel(input[0]))
2420
.then(console.log);
2521
}
2622
}

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
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { InitOptions } from '../types/init-options.interface';
88
import { Injectable } from '@nestjs/common';
99
import { firstValueFrom } from 'rxjs';
1010
import { FileManagerService } from '@/file-manager/file-manager.service';
11+
import { rm } from 'fs/promises';
1112

1213
@Injectable()
1314
export class InitCliUsecases {
@@ -105,6 +106,7 @@ export class InitCliUsecases {
105106
console.error('Error decompressing file', e);
106107
exit(1);
107108
}
109+
await rm(destination, { force: true });
108110
};
109111

110112
parseEngineFileName = (options: InitOptions) => {
@@ -228,5 +230,6 @@ export class InitCliUsecases {
228230
console.log(e);
229231
exit(1);
230232
}
233+
await rm(destination, { force: true });
231234
};
232235
}

cortex-js/src/infrastructure/controllers/cortex.controller.spec.ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

cortex-js/src/infrastructure/controllers/cortex.controller.ts

Lines changed: 0 additions & 45 deletions
This file was deleted.

0 commit comments

Comments
 (0)