Skip to content

Commit 93dfbc3

Browse files
added prompt assist to token balance system
1 parent 4ad62cb commit 93dfbc3

1 file changed

Lines changed: 148 additions & 19 deletions

File tree

api/server/routes/promptAssist.js

Lines changed: 148 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
const express = require('express');
22
const OpenAI = require('openai');
3-
const { getCustomConfig } = require('~/server/services/Config');
3+
const { promptTokensEstimate } = require('openai-chat-tokens');
4+
const { EModelEndpoint, supportsBalanceCheck } = require('librechat-data-provider');
5+
const { getCustomConfig, getBalanceConfig } = require('~/server/services/Config');
46
const { requireJwtAuth } = require('~/server/middleware');
7+
const { checkBalance } = require('~/models/balanceMethods');
8+
const { spendTokens } = require('~/models/spendTokens');
9+
const { getValueKey } = require('~/models/tx');
510
const { logger } = require('~/config');
611

712
const router = express.Router();
@@ -35,21 +40,17 @@ router.post('/', requireJwtAuth, async (req, res) => {
3540
apiKey: process.env.OPENAI_API_KEY,
3641
});
3742

38-
// Construct the prompt for the LLM
39-
const variablesSection = availableVariables && availableVariables.length > 0
40-
? `\n\nAvailable Variables (use these when appropriate):
41-
${availableVariables.map(v => `- ${v.syntax}: ${v.description}`).join('\n')}
42-
43-
When enhancing the prompt, consider incorporating these variables where they would be useful. For example, if the assistant needs current information, suggest using {{current_date}} or {{current_datetime}}. If it should personalize responses, mention {{current_user}}.`
44-
: '';
45-
43+
// Prepare messages for token estimation
4644
const systemPrompt = `You are an expert at writing clear, effective prompts for AI assistants.
4745
Your task is to enhance the given instructions to make them more clear, comprehensive, and effective.
4846
49-
IMPORTANT FORMATTING RULES:
47+
CRITICAL FORMATTING RULES - FOLLOW EXACTLY:
5048
- Do NOT include the title or description in your response (they are already set by the user)
51-
- Do NOT use markdown formatting like **bold** or ##headers
52-
- Use plain text with clear structure using dashes, numbers, or bullet points
49+
- NEVER use asterisks (*) or double asterisks (**) for ANY reason
50+
- NEVER use markdown formatting like **bold**, *italic*, ##headers, or backticks
51+
- NEVER write **Target Audience** or **Value Proposition** - write Target Audience or VALUE PROPOSITION instead
52+
- Use ONLY plain text with numbers (1. 2. 3.) or simple dashes (-) for structure
53+
- For emphasis use CAPITAL LETTERS, not asterisks
5354
- Start directly with the enhanced instructions content
5455
5556
The enhanced prompt should:
@@ -58,7 +59,12 @@ The enhanced prompt should:
5859
- Specify the desired output format when applicable
5960
- Include examples if helpful
6061
- Be well-structured and easy to follow
61-
- Incorporate dynamic variables when they would enhance the functionality${variablesSection}
62+
- Incorporate dynamic variables when they would enhance the functionality${availableVariables && availableVariables.length > 0
63+
? `\n\nAvailable Variables (use these when appropriate):
64+
${availableVariables.map(v => `- ${v.syntax}: ${v.description}`).join('\n')}
65+
66+
When enhancing the prompt, consider incorporating these variables where they would be useful. For example, if the assistant needs current information, suggest using {{current_date}} or {{current_datetime}}. If it should personalize responses, mention {{current_user}}.`
67+
: ''}
6268
6369
Return ONLY the enhanced instructions content without any title, description, headers, or markdown formatting.`;
6470

@@ -70,12 +76,41 @@ Current Instructions: ${instructions || 'No instructions provided yet'}
7076
7177
Create enhanced instructions that will help the AI assistant perform its intended function effectively. Consider incorporating the available variables where they would be beneficial. Remember to return only the instructions content without repeating the title or description.`;
7278

73-
// Use OpenAI client directly
79+
// Estimate token usage for balance check
7480
const messages = [
7581
{ role: 'system', content: systemPrompt },
7682
{ role: 'user', content: userPrompt }
7783
];
7884

85+
const promptTokens = promptTokensEstimate({ messages, model });
86+
const estimatedCompletionTokens = 1000; // Max tokens we're requesting
87+
88+
// Check balance if enabled
89+
const balanceConfig = await getBalanceConfig();
90+
if (balanceConfig?.enabled && supportsBalanceCheck[EModelEndpoint.openAI]) {
91+
try {
92+
await checkBalance({
93+
req,
94+
res,
95+
txData: {
96+
user: req.user.id,
97+
tokenType: 'prompt',
98+
amount: promptTokens + estimatedCompletionTokens,
99+
model,
100+
endpoint: EModelEndpoint.openAI,
101+
context: 'prompt-assist',
102+
},
103+
});
104+
} catch (err) {
105+
logger.error('[/api/prompt-assist] Balance check failed:', err);
106+
return res.status(402).json({
107+
error: 'Insufficient balance',
108+
details: err.message
109+
});
110+
}
111+
}
112+
113+
// Use OpenAI client directly
79114
const response = await openai.chat.completions.create({
80115
model,
81116
messages,
@@ -85,6 +120,31 @@ Create enhanced instructions that will help the AI assistant perform its intende
85120

86121
const enhancedPrompt = response.choices[0]?.message?.content || '';
87122

123+
// Log token usage
124+
if (response.usage) {
125+
logger.info(`[/api/prompt-assist] Token usage for instruction enhancement - Total: ${response.usage.total_tokens} tokens (prompt: ${response.usage.prompt_tokens}, completion: ${response.usage.completion_tokens}) for user: ${req.user.id} using model: ${model}`);
126+
}
127+
128+
// Record token usage
129+
if (balanceConfig?.enabled && response.usage) {
130+
const { prompt_tokens, completion_tokens } = response.usage;
131+
await spendTokens(
132+
{
133+
user: req.user.id,
134+
conversationId: 'prompt-assist',
135+
model,
136+
context: 'prompt-assist',
137+
endpoint: EModelEndpoint.openAI,
138+
endpointTokenConfig: customConfig?.endpoints?.[EModelEndpoint.openAI]?.tokenConfig,
139+
valueKey: getValueKey(model, EModelEndpoint.openAI),
140+
},
141+
{
142+
promptTokens: prompt_tokens,
143+
completionTokens: completion_tokens,
144+
}
145+
);
146+
}
147+
88148
res.json({ enhancedPrompt });
89149
} catch (error) {
90150
logger.error('[/api/prompt-assist] Error enhancing prompt:', error);
@@ -125,6 +185,7 @@ router.post('/enhance-message', requireJwtAuth, async (req, res) => {
125185
apiKey: process.env.OPENAI_API_KEY,
126186
});
127187

188+
// Prepare system prompt
128189
const systemPrompt = `You are an expert at improving user messages to AI assistants to make them much clearer, more specific, and more effective for getting high-quality responses.
129190
130191
Your task is to significantly enhance the user's message while preserving their original intent. The enhancement should:
@@ -147,24 +208,92 @@ Examples:
147208
- "help me write code" → "Help me write clean, well-documented Python code for [specific functionality]. Include error handling, follow PEP 8 standards, and add inline comments explaining the logic. Provide the complete code with example usage."
148209
- "make a sales email" → "Create a professional sales email template for B2B cold outreach targeting [specific industry/role]. The email should be personalized, include a clear value proposition, have a compelling subject line, and end with a specific call-to-action. Keep it under 150 words and maintain a consultative tone."
149210
150-
Return the enhanced message as plain text.`;
211+
Return the enhanced message as plain text.
212+
213+
CRITICAL FORMATTING RULES - YOU MUST FOLLOW THESE:
214+
- NEVER use asterisks (*) or double asterisks (**) for ANY reason
215+
- NEVER use markdown formatting of any kind
216+
- NEVER write **bold text** - write BOLD TEXT or Bold Text instead
217+
- NEVER use backticks for code or formatting
218+
- Use ONLY plain text with clear structure
219+
- Use ONLY numbers (1. 2. 3.) or simple dashes (-) for lists
220+
- For emphasis, use CAPITAL LETTERS instead of asterisks
221+
- Write headings as plain text (e.g., "Target Audience:" not "**Target Audience**")`;
151222

152223
const userPrompt = `Transform this user message into a detailed, comprehensive prompt that will help an AI assistant provide the best possible response:
153224
154225
${message}`;
155226

227+
// Prepare messages for API call
228+
const messages = [
229+
{ role: 'system', content: systemPrompt },
230+
{ role: 'user', content: userPrompt }
231+
];
232+
233+
// Estimate token usage for balance check
234+
const promptTokens = promptTokensEstimate({ messages, model });
235+
const estimatedCompletionTokens = 500; // Max tokens we're requesting
236+
237+
// Check balance if enabled
238+
const balanceConfig = await getBalanceConfig();
239+
if (balanceConfig?.enabled && supportsBalanceCheck[EModelEndpoint.openAI]) {
240+
try {
241+
await checkBalance({
242+
req,
243+
res,
244+
txData: {
245+
user: req.user.id,
246+
tokenType: 'prompt',
247+
amount: promptTokens + estimatedCompletionTokens,
248+
model,
249+
endpoint: EModelEndpoint.openAI,
250+
context: 'prompt-assist-message',
251+
},
252+
});
253+
} catch (err) {
254+
logger.error('[/api/prompt-assist/enhance-message] Balance check failed:', err);
255+
return res.status(402).json({
256+
error: 'Insufficient balance',
257+
details: err.message,
258+
originalMessage: message
259+
});
260+
}
261+
}
262+
156263
const response = await openai.chat.completions.create({
157264
model,
158-
messages: [
159-
{ role: 'system', content: systemPrompt },
160-
{ role: 'user', content: userPrompt }
161-
],
265+
messages,
162266
temperature: 0.3,
163267
max_tokens: 500,
164268
});
165269

166270
const enhancedMessage = response.choices[0]?.message?.content || message;
167271

272+
// Log token usage
273+
if (response.usage) {
274+
logger.info(`[/api/prompt-assist/enhance-message] Token usage for message enhancement - Total: ${response.usage.total_tokens} tokens (prompt: ${response.usage.prompt_tokens}, completion: ${response.usage.completion_tokens}) for user: ${req.user.id} using model: ${model}`);
275+
}
276+
277+
// Record token usage
278+
if (balanceConfig?.enabled && response.usage) {
279+
const { prompt_tokens, completion_tokens } = response.usage;
280+
await spendTokens(
281+
{
282+
user: req.user.id,
283+
conversationId: 'prompt-assist-message',
284+
model,
285+
context: 'prompt-assist-message',
286+
endpoint: EModelEndpoint.openAI,
287+
endpointTokenConfig: customConfig?.endpoints?.[EModelEndpoint.openAI]?.tokenConfig,
288+
valueKey: getValueKey(model, EModelEndpoint.openAI),
289+
},
290+
{
291+
promptTokens: prompt_tokens,
292+
completionTokens: completion_tokens,
293+
}
294+
);
295+
}
296+
168297
res.json({ enhancedMessage });
169298
} catch (error) {
170299
logger.error('[/api/prompt-assist/enhance-message] Error enhancing message:', error);

0 commit comments

Comments
 (0)