Merge pull request #1849 from xKevIsDev/mcp-token-usage
fix: add text sanitization function to clean user and assistant messages of new parts object
This commit is contained in:
@@ -26,6 +26,14 @@ export interface StreamingOptions extends Omit<Parameters<typeof _streamText>[0]
|
||||
|
||||
const logger = createScopedLogger('stream-text');
|
||||
|
||||
function sanitizeText(text: string): string {
|
||||
let sanitized = text.replace(/<div class=\\"__boltThought__\\">.*?<\/div>/s, '');
|
||||
sanitized = sanitized.replace(/<think>.*?<\/think>/s, '');
|
||||
sanitized = sanitized.replace(/<boltAction type="file" filePath="package-lock\.json">[\s\S]*?<\/boltAction>/g, '');
|
||||
|
||||
return sanitized.trim();
|
||||
}
|
||||
|
||||
export async function streamText(props: {
|
||||
messages: Omit<Message, 'id'>[];
|
||||
env?: Env;
|
||||
@@ -58,30 +66,25 @@ export async function streamText(props: {
|
||||
let currentModel = DEFAULT_MODEL;
|
||||
let currentProvider = DEFAULT_PROVIDER.name;
|
||||
let processedMessages = messages.map((message) => {
|
||||
const newMessage = { ...message };
|
||||
|
||||
if (message.role === 'user') {
|
||||
const { model, provider, content } = extractPropertiesFromMessage(message);
|
||||
currentModel = model;
|
||||
currentProvider = provider;
|
||||
|
||||
return { ...message, content };
|
||||
newMessage.content = sanitizeText(content);
|
||||
} else if (message.role == 'assistant') {
|
||||
let content = message.content;
|
||||
content = content.replace(/<div class=\\"__boltThought__\\">.*?<\/div>/s, '');
|
||||
content = content.replace(/<think>.*?<\/think>/s, '');
|
||||
|
||||
// Remove package-lock.json content specifically keeping token usage MUCH lower
|
||||
content = content.replace(
|
||||
/<boltAction type="file" filePath="package-lock\.json">[\s\S]*?<\/boltAction>/g,
|
||||
'[package-lock.json content removed]',
|
||||
);
|
||||
|
||||
// Trim whitespace potentially left after removals
|
||||
content = content.trim();
|
||||
|
||||
return { ...message, content };
|
||||
newMessage.content = sanitizeText(message.content);
|
||||
}
|
||||
|
||||
return message;
|
||||
// Sanitize all text parts in parts array, if present
|
||||
if (Array.isArray(message.parts)) {
|
||||
newMessage.parts = message.parts.map((part) =>
|
||||
part.type === 'text' ? { ...part, text: sanitizeText(part.text) } : part,
|
||||
);
|
||||
}
|
||||
|
||||
return newMessage;
|
||||
});
|
||||
|
||||
const provider = PROVIDER_LIST.find((p) => p.name === currentProvider) || DEFAULT_PROVIDER;
|
||||
|
||||
@@ -65,6 +65,13 @@ The year is 2025.
|
||||
: ''
|
||||
}
|
||||
|
||||
|
||||
${
|
||||
supabase?.isConnected &&
|
||||
supabase?.hasSelectedProject &&
|
||||
supabase?.credentials?.supabaseUrl &&
|
||||
supabase?.credentials?.anonKey
|
||||
? `
|
||||
Create .env file if it doesn't exist${
|
||||
supabase?.isConnected &&
|
||||
supabase?.hasSelectedProject &&
|
||||
@@ -75,10 +82,6 @@ The year is 2025.
|
||||
VITE_SUPABASE_ANON_KEY=${supabase.credentials.anonKey}`
|
||||
: '.'
|
||||
}
|
||||
|
||||
NEVER modify Supabase config or .env files apart from creating .env.
|
||||
Do not generate types for supabase.
|
||||
|
||||
DATA PRESERVATION REQUIREMENTS:
|
||||
- DATA INTEGRITY IS HIGHEST PRIORITY - users must NEVER lose data
|
||||
- FORBIDDEN: Destructive operations (DROP, DELETE) that could cause data loss
|
||||
@@ -131,6 +134,9 @@ The year is 2025.
|
||||
- One migration per logical change
|
||||
- Use descriptive policy names
|
||||
- Add indexes for frequently queried columns
|
||||
`
|
||||
: ''
|
||||
}
|
||||
</database_instructions>
|
||||
|
||||
<artifact_instructions>
|
||||
|
||||
@@ -597,7 +597,11 @@ export class FilesStore {
|
||||
|
||||
// Set up file watcher
|
||||
webcontainer.internal.watchPaths(
|
||||
{ include: [`${WORK_DIR}/**`], exclude: ['**/node_modules', '.git'], includeContent: true },
|
||||
{
|
||||
include: [`${WORK_DIR}/**`],
|
||||
exclude: ['**/node_modules', '.git', '**/package-lock.json'],
|
||||
includeContent: true,
|
||||
},
|
||||
bufferWatchEvents(100, this.#processEventBuffer.bind(this)),
|
||||
);
|
||||
|
||||
|
||||
@@ -151,45 +151,6 @@ export class PreviewsStore {
|
||||
this._broadcastStorageSync();
|
||||
});
|
||||
|
||||
try {
|
||||
// Watch for file changes
|
||||
webcontainer.internal.watchPaths(
|
||||
{
|
||||
// Only watch specific file types that affect the preview
|
||||
include: ['**/*.html', '**/*.css', '**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx', '**/*.json'],
|
||||
exclude: ['**/node_modules/**', '**/.git/**', '**/dist/**', '**/build/**', '**/coverage/**'],
|
||||
},
|
||||
async (_events) => {
|
||||
const previews = this.previews.get();
|
||||
|
||||
for (const preview of previews) {
|
||||
const previewId = this.getPreviewId(preview.baseUrl);
|
||||
|
||||
if (previewId) {
|
||||
this.broadcastFileChange(previewId);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Watch for DOM changes that might affect storage
|
||||
if (typeof window !== 'undefined') {
|
||||
const observer = new MutationObserver((_mutations) => {
|
||||
// Broadcast storage changes when DOM changes
|
||||
this._broadcastStorageSync();
|
||||
});
|
||||
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
characterData: true,
|
||||
attributes: true,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Preview] Error setting up watchers:', error);
|
||||
}
|
||||
|
||||
// Listen for port events
|
||||
webcontainer.on('port', (port, type, url) => {
|
||||
let previewInfo = this.#availablePreviews.get(port);
|
||||
|
||||
Reference in New Issue
Block a user