Skip to content

Commit a114871

Browse files
committed
feat(rag-cli): add create message and topic functionality
1 parent 01f16ca commit a114871

File tree

4 files changed

+168
-29
lines changed

4 files changed

+168
-29
lines changed

clients/agentic-rag-cli/index.ts

Lines changed: 163 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,22 @@
22

33
import fs from 'fs';
44
import path from 'path';
5-
import { TrieveSDK } from 'trieve-ts-sdk';
5+
import { TrieveSDK, Topic } from 'trieve-ts-sdk';
66
import { program } from 'commander';
77
import chalk from 'chalk';
88
import inquirer from 'inquirer';
99
import Conf from 'conf';
10+
import os from 'os';
1011

11-
// Use XDG_CONFIG_HOME or default to ~/.config
12-
const configDir =
13-
process.env.XDG_CONFIG_HOME || `${require('os').homedir()}/.config`;
12+
interface UploadedFile {
13+
fileName: string;
14+
filePath: string;
15+
trackingId: string;
16+
uploadedAt: string;
17+
status: 'pending' | 'completed';
18+
}
19+
20+
const configDir = process.env.XDG_CONFIG_HOME || `${os.homedir()}/.config`;
1421
const config = new Conf({
1522
cwd: `${configDir}/trieve-cli`,
1623
configName: 'config',
@@ -22,14 +29,8 @@ const uploadedFilesPath = path.join(
2229
'uploaded_files.json',
2330
);
2431

25-
// File tracking interface
26-
interface UploadedFile {
27-
fileName: string;
28-
filePath: string;
29-
trackingId: string;
30-
uploadedAt: string;
31-
status?: 'pending' | 'completed';
32-
}
32+
// Path for storing topics data
33+
const topicsPath = path.join(`${configDir}/trieve-cli`, 'topics.json');
3334

3435
// Function to manage uploaded files tracking
3536
function manageUploadedFiles(
@@ -68,8 +69,39 @@ function manageUploadedFiles(
6869
}
6970
}
7071

71-
function getConfigOrEnv(key: string, envVar: string) {
72-
return process.env[envVar] || config.get(key);
72+
// Function to manage topics
73+
function manageTopics(action: 'get' | 'add', topicData?: Topic): Topic[] {
74+
try {
75+
// Create the directory if it doesn't exist
76+
if (!fs.existsSync(path.dirname(topicsPath))) {
77+
fs.mkdirSync(path.dirname(topicsPath), { recursive: true });
78+
}
79+
80+
// Initialize or read existing data
81+
let topics: Topic[] = [];
82+
if (fs.existsSync(topicsPath)) {
83+
const fileContent = fs.readFileSync(topicsPath, 'utf-8');
84+
topics = fileContent ? JSON.parse(fileContent) : [];
85+
}
86+
87+
if (action === 'add' && topicData) {
88+
// Add new topic data
89+
topics.push(topicData);
90+
fs.writeFileSync(topicsPath, JSON.stringify(topics, null, 2));
91+
}
92+
93+
return topics;
94+
} catch (error) {
95+
console.error(
96+
chalk.red('❌ Error managing topics:'),
97+
error instanceof Error ? error.message : error,
98+
);
99+
return [];
100+
}
101+
}
102+
103+
function getConfigOrEnv(key: string, envVar: string): string | undefined {
104+
return process.env[envVar] || (config.get(key) as string);
73105
}
74106

75107
function ensureTrieveConfig() {
@@ -180,30 +212,25 @@ async function promptForFile() {
180212
}
181213
}
182214

183-
// Function to check file upload status using tracking ID
184-
async function checkFileUploadStatus(trackingId: string): Promise<boolean> {
215+
async function checkFileUploadStatus(
216+
groupTrackingId: string,
217+
): Promise<boolean> {
185218
try {
186219
const { apiKey, datasetId } = ensureTrieveConfig();
187220
const trieveClient: TrieveSDK = new TrieveSDK({
188221
apiKey,
189222
datasetId,
190223
});
191224

192-
// Call the API to check the status
193-
const response = await trieveClient.getChunksGroupByTrackingId(
194-
trackingId,
195-
1,
196-
);
225+
const response = await trieveClient.getChunksGroupByTrackingId({
226+
groupTrackingId,
227+
page: 1,
228+
});
197229

198-
// If we get chunks back, the file is processed
199230
const isCompleted = response.chunks && response.chunks.length > 0;
200231

201232
return isCompleted;
202233
} catch (error) {
203-
console.error(
204-
chalk.red(`❌ Failed to check status for tracking ID ${trackingId}:`),
205-
error instanceof Error ? error.message : error,
206-
);
207234
return false;
208235
}
209236
}
@@ -327,6 +354,80 @@ async function interactiveCheckStatus(): Promise<void> {
327354
}
328355
}
329356

357+
// Function to ask a question and stream back the response
358+
async function askQuestion(question: string): Promise<void> {
359+
try {
360+
console.log(chalk.blue('🤔 Processing your question...'));
361+
362+
const { apiKey, datasetId } = ensureTrieveConfig();
363+
const trieveClient: TrieveSDK = new TrieveSDK({
364+
apiKey,
365+
datasetId,
366+
});
367+
368+
// Generate a topic name from the question (use first few words)
369+
const topicName = question.split(' ').slice(0, 5).join(' ') + '...';
370+
371+
// Create a topic
372+
console.log(chalk.blue('📝 Creating a new topic...'));
373+
const ownerId =
374+
(config.get('userId') as string) ||
375+
'default-user-' + Math.random().toString(36).substring(2, 15);
376+
377+
const topicData = await trieveClient.createTopic({
378+
first_user_message: question,
379+
name: topicName,
380+
owner_id: ownerId,
381+
});
382+
383+
// Save the topic for future reference
384+
manageTopics('add', topicData as Topic);
385+
386+
console.log(chalk.green(`✅ Topic created: ${topicName}`));
387+
console.log(chalk.blue('🔍 Fetching answer...'));
388+
389+
// Create a message and stream the response
390+
const { reader, queryId } =
391+
await trieveClient.createMessageReaderWithQueryId({
392+
topic_id: topicData.id,
393+
new_message_content: question,
394+
});
395+
396+
console.log(chalk.yellow('\n🤖 Answer:'));
397+
console.log('─'.repeat(80));
398+
399+
// Stream the response
400+
const decoder = new TextDecoder();
401+
let answer = '';
402+
403+
try {
404+
while (true) {
405+
const { done, value } = await reader.read();
406+
if (done) break;
407+
408+
const chunk = decoder.decode(value);
409+
answer += chunk;
410+
process.stdout.write(chunk);
411+
}
412+
} catch (e) {
413+
console.error(chalk.red('❌ Error streaming response:'), e);
414+
} finally {
415+
reader.releaseLock();
416+
}
417+
418+
console.log('\n' + '─'.repeat(80));
419+
console.log(chalk.green('✅ Response complete'));
420+
console.log(
421+
chalk.blue(`📚 Topic ID: ${topicData.id} (saved for future reference)`),
422+
);
423+
} catch (error) {
424+
console.error(
425+
chalk.red('❌ Failed to process question:'),
426+
error instanceof Error ? error.message : error,
427+
);
428+
}
429+
}
430+
330431
program
331432
.name('trieve-cli')
332433
.description('A CLI tool for using Trieve')
@@ -362,9 +463,16 @@ program
362463
message: 'Enter your TRIEVE_DATASET_ID:',
363464
default: (config.get('TRIEVE_DATASET_ID') as string) || '',
364465
},
466+
{
467+
type: 'input',
468+
name: 'userId',
469+
message: 'Enter your user ID (for topic ownership):',
470+
default: (config.get('userId') as string) || '',
471+
},
365472
]);
366473
config.set('TRIEVE_API_KEY', answers.TRIEVE_API_KEY);
367474
config.set('TRIEVE_DATASET_ID', answers.TRIEVE_DATASET_ID);
475+
config.set('userId', answers.userId);
368476
console.log(chalk.green('✅ Configuration saved!'));
369477
});
370478

@@ -386,6 +494,33 @@ program
386494
}
387495
});
388496

497+
program
498+
.command('ask')
499+
.description('Ask a question and get a streamed response')
500+
.argument('<question>', 'The question to ask')
501+
.action(async (question) => {
502+
await askQuestion(question);
503+
});
504+
505+
program
506+
.command('interactive-ask')
507+
.description('Ask a question interactively and get a streamed response')
508+
.action(async () => {
509+
const answers = await inquirer.prompt([
510+
{
511+
type: 'input',
512+
name: 'question',
513+
message: 'What would you like to ask?',
514+
validate: (input) => {
515+
if (!input) return 'Question is required';
516+
return true;
517+
},
518+
},
519+
]);
520+
521+
await askQuestion(answers.question);
522+
});
523+
389524
program.addHelpText(
390525
'after',
391526
`
@@ -395,6 +530,8 @@ ${chalk.yellow('Examples:')}
395530
$ ${chalk.green('trieve-cli check-upload-status')}
396531
$ ${chalk.green('trieve-cli check-upload-status --all')}
397532
$ ${chalk.green('trieve-cli check-upload-status --tracking-id <tracking-id>')}
533+
$ ${chalk.green('trieve-cli ask "What is the capital of France?"')}
534+
$ ${chalk.green('trieve-cli interactive-ask')}
398535
`,
399536
);
400537

clients/agentic-rag-cli/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"name": "agentic-rag-cli",
33
"version": "1.0.0",
4+
"type": "module",
45
"main": "dist/index.js",
56
"bin": {
67
"trieve-cli": "dist/index.js"
@@ -27,7 +28,7 @@
2728
"dependencies": {
2829
"chalk": "^5.4.1",
2930
"commander": "^14.0.0",
30-
"conf": "^11.0.0",
31+
"conf": "^14.0.0",
3132
"inquirer": "^12.6.3",
3233
"trieve-ts-sdk": "^0.0.118"
3334
}

clients/agentic-rag-cli/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{
22
"compilerOptions": {
33
"target": "ES2020",
4-
"module": "nodenext",
4+
"module": "es2020",
5+
"moduleResolution": "bundler",
56
"outDir": "dist",
67
"rootDir": ".",
78
"strict": true,

clients/ts-sdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"files": [
1818
"dist"
1919
],
20-
"version": "0.0.118",
20+
"version": "0.0.119",
2121
"license": "MIT",
2222
"scripts": {
2323
"lint": "eslint 'src/**/*.ts'",

0 commit comments

Comments
 (0)