Skip to content

Commit 5333d16

Browse files
author
mmiscool
committed
Added concept of conversation threads that are persistent
1 parent 82075a6 commit 5333d16

File tree

2 files changed

+87
-40
lines changed

2 files changed

+87
-40
lines changed

src/llmCall.js

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,36 @@ import {
1010
} from "./terminalHelpers.js";
1111
import Anthropic from '@anthropic-ai/sdk';
1212
import cliProgress from 'cli-progress';
13-
import { spawn } from 'child_process';``
13+
import { spawn } from 'child_process'; ``
1414

1515
let throttleTime = 20;
1616
let lastCallTime = 0;
1717

1818
export class conversation {
19-
constructor() {
19+
constructor(id = null, targetFile = null) {
2020
this.messages = [];
21+
this.title = '';
22+
this.targetFile = targetFile;
23+
24+
if (id) {
25+
this.id = id;
26+
this.loadConversation(id);
27+
} else {
28+
//generate a unique id for the conversation based on the current time in the format
29+
// of yyyy-mm-dd-hh-mm-ss
30+
this.id = new Date().toISOString().replace(/[-:.]/g, '').replace('T', '_').split('.')[0];
31+
}
32+
2133
}
2234

2335
async addMessage(role, content) {
2436
this.messages.push({ role, content });
37+
this.storeConversation();
2538
}
2639

2740
async addFileMessage(role, filePath, description = '') {
2841
this.messages.push({ role, content: filePath, filePath, description });
42+
this.storeConversation();
2943
}
3044

3145
async lastMessage() {
@@ -42,9 +56,70 @@ export class conversation {
4256
async getMessages() {
4357
return this.messages;
4458
}
59+
60+
async getConversation() {
61+
return {
62+
messages: this.messages,
63+
title: this.title,
64+
id: this.id,
65+
targetFile: this.targetFile
66+
}
67+
}
68+
69+
async clearMessages() {
70+
this.messages = [];
71+
this.storeConversation();
72+
}
73+
74+
async storeConversation(id = this.id) {
75+
// write the conversation to a file
76+
const conversationObject = {
77+
messages: this.messages,
78+
title: this.title,
79+
id: this.id,
80+
targetFile: this.targetFile
81+
};
82+
const conversationJSON = JSON.stringify(conversationObject);
83+
const filePath = `./.aiCoder/conversations/${id}.json`;
84+
await writeFile(filePath, conversationJSON);
85+
86+
}
87+
88+
async loadConversation(id = this.id) {
89+
// load the conversation from a file
90+
const filePath = `./.aiCoder/conversations/${id}.json`;
91+
92+
const conversationJSON = await readFile(filePath);
93+
const conversationObject = JSON.parse(conversationJSON);
94+
this.messages = conversationObject.messages;
95+
this.title = conversationObject.title;
96+
this.id = conversationObject.id;
97+
this.targetFile = conversationObject.targetFile;
98+
}
4599
}
46100

47101

102+
103+
export async function listConversations() {
104+
// load all the conversations from the conversation folder
105+
const conversationFolder = './.aiCoder/conversations';
106+
if (!fs.existsSync
107+
(conversationFolder)) {
108+
fs.mkdirSync(conversationFolder);
109+
}
110+
111+
const conversationFiles = fs.readdirSync(conversationFolder);
112+
for (const file of conversationFiles) {
113+
const conversationId = file.split('.')[0];
114+
const newConversation = new conversation(conversationId);
115+
this.conversations.push(newConversation);
116+
}
117+
118+
return this.conversations;
119+
}
120+
121+
122+
48123
async function throttle() {
49124
// check if the current time is greater than the last call time + throttle time and if not wait until it is
50125
// if it needs use the printAndPause function to show a message to the user and wait the remaining time
@@ -185,14 +260,14 @@ export async function selectModel(overwrite = false) {
185260
const llmModelFileName = `./.aiCoder/${await selectAIservice()}-model.txt`;
186261
if (readFile(llmModelFileName) && !overwrite) {
187262
return readFile(llmModelFileName);
188-
}
263+
}
189264
}
190265

191266

192267
export async function selectAIservice(overwrite = false) {
193268
if (fs.existsSync('./.aiCoder/ai-service.txt') && !overwrite) {
194269
return fs.readFileSync('./.aiCoder/ai-service.txt', 'utf8');
195-
}
270+
}
196271
}
197272

198273
// ollama related functions -----------------------------------------------------------------------------------------------

src/main.js

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env node
22
import {
3-
printAndPause,
3+
printAndPause,
44
} from './terminalHelpers.js';
55

66
import './gitnoteSetup.js';
@@ -13,8 +13,8 @@ export const debugMode = false;
1313

1414
// graceful shutdown
1515
process.on('SIGINT', () => {
16-
printAndPause("\nExiting gracefully...");
17-
process.exit(0); // Exit with a success code
16+
printAndPause("\nExiting gracefully...");
17+
process.exit(0); // Exit with a success code
1818
});
1919

2020

@@ -26,42 +26,14 @@ ctx.skipApprovingChanges = false;
2626

2727

2828
async function appStart(params) {
29-
if (!ctx.targetFile) ctx.targetFile = await getFilePath();
30-
setupServer();
29+
if (!ctx.targetFile) ctx.targetFile = await getFilePath();
30+
setupServer();
3131
}
3232

3333
// Determine file path based on argument or interactive selection
3434
export async function getFilePath(newFilePathArg = null) {
35-
const filePath = newFilePathArg;
36-
newFilePathArg = await fileSelector({
37-
message: 'Select a file:',
38-
pageSize: await selectListHeight() - 2,
39-
filter: (filePath) => {
40-
printDebugMessage(filePath);
41-
//return true;
42-
if (filePath.path.includes(
43-
'node_modules') ||
44-
filePath.path.includes('.git') ||
45-
filePath.path.includes('.vscode')
46-
) {
47-
return false;
48-
}
49-
50-
// check if the file starts with a dot
51-
if (filePath.path.includes('/.')) {
52-
return false;
53-
}
54-
55-
return true;
56-
}
57-
58-
});
59-
60-
//convert to relative path taking into account the git root
61-
newFilePathArg = await path.relative(process.cwd(), newFilePathArg);
62-
63-
return `./${newFilePathArg}`;
64-
}
65-
35+
return `./`;
36+
}
37+
6638

6739
appStart();

0 commit comments

Comments
 (0)