fix: fix prompt continuation

This commit is contained in:
Daniel Woelfel 2025-05-21 13:52:53 -07:00
parent f0aa58c922
commit 3e1bcb9849
No known key found for this signature in database
GPG Key ID: 52E90E357B942D32
6 changed files with 87 additions and 25 deletions

View File

@ -531,7 +531,9 @@ export const ChatImpl = memo(
description={description}
importChat={importChat}
exportChat={exportChat}
messages={messages.map((message, i) => {
messages={messages
.filter((message, i) => (message.role === 'assistant' ? parsedMessages[i] : true))
.map((message, i) => {
if (message.role === 'user') {
return message;
}

View File

@ -1,6 +1,5 @@
import { WORK_DIR } from '~/utils/constants';
import { allowedHTMLElements } from '~/utils/markdown';
import { stripIndents } from '~/utils/stripIndent';
export const getFineTunedPrompt = (
cwd: string = WORK_DIR,
@ -695,7 +694,12 @@ npm run dev
</example>
</examples>`;
export const CONTINUE_PROMPT = stripIndents`
Continue your prior response. IMPORTANT: Immediately begin from where you left off without any interruptions.
Do not repeat any content, including artifact and action tags.
`;
export const CONTINUE_PROMPT = `Continue your prior response.
Important: continue your last message without any interruptions, even if you're in the middle of a thought. You are continuing a document that will be re-assembled later. Never repeat any text that has already been sent.
Example:
Previous message:
<boltAction filePath="index.html"><!DOCTYPE html><html lang
Bad: Repeats the previous message. This creates an unreadable document.
<boltAction filePath="index.html"><!DOCTYPE html><html lang="en"><body>
Good: Continues from where the previous message left off:
="en"><body>`;

View File

@ -698,7 +698,12 @@ Here are some examples of correct usage of artifacts:
</examples>
`;
export const CONTINUE_PROMPT = stripIndents`
Continue your prior response. IMPORTANT: Immediately begin from where you left off without any interruptions.
Do not repeat any content, including artifact and action tags.
`;
export const CONTINUE_PROMPT = `Continue your prior response.
Important: continue your last message without any interruptions, even if you're in the middle of a thought. You are continuing a document that will be re-assembled later. Never repeat any text that has already been sent.
Example:
Previous message:
<boltAction filePath="index.html"><!DOCTYPE html><html lang
Bad: Repeats the previous message. This creates an unreadable document.
<boltAction filePath="index.html"><!DOCTYPE html><html lang="en"><body>
Good: Continues from where the previous message left off:
="en"><body>`;

View File

@ -1,7 +1,8 @@
import type { Message } from 'ai';
import type { JSONValue, Message } from 'ai';
import { useCallback, useState } from 'react';
import { StreamingMessageParser } from '~/lib/runtime/message-parser';
import { workbenchStore } from '~/lib/stores/workbench';
import type { SegmentsGroupAnnotation } from '~/types/context';
import { createScopedLogger } from '~/utils/logger';
const logger = createScopedLogger('useMessageParser');
@ -47,6 +48,14 @@ const extractTextContent = (message: Message) =>
? (message.content.find((item) => item.type === 'text')?.text as string) || ''
: message.content;
const segmentsGroupIdFromAnnotation = (annotation: JSONValue): string | null => {
if (annotation && typeof annotation === 'object' && 'type' in annotation && annotation.type === 'segmentsGroup') {
return (annotation as SegmentsGroupAnnotation).segmentsGroupId;
}
return null;
};
export function useMessageParser() {
const [parsedMessages, setParsedMessages] = useState<{ [key: number]: string }>({});
@ -58,15 +67,46 @@ export function useMessageParser() {
messageParser.reset();
}
const messageContents: Record<number, string> = {};
const segmentGroups: Record<string, { firstGroupIndex: number }> = {};
for (const [index, message] of messages.entries()) {
if (message.role === 'user') {
messageContents[index] = extractTextContent(message);
} else if (message.role === 'assistant') {
const segmentsGroupId = message.annotations?.reduce(
(groupId: string | null, a) => groupId ?? segmentsGroupIdFromAnnotation(a),
null,
);
if (!segmentsGroupId) {
messageContents[index] = extractTextContent(message);
} else {
const firstIndex = segmentGroups[segmentsGroupId]?.firstGroupIndex;
if (firstIndex === undefined) {
segmentGroups[segmentsGroupId] = { firstGroupIndex: index };
messageContents[index] = extractTextContent(message);
} else {
messageContents[firstIndex] += extractTextContent(message);
}
}
}
}
for (const [index, message] of messages.entries()) {
if (message.role === 'assistant' || message.role === 'user') {
const newParsedContent = messageParser.parse(message.id, extractTextContent(message));
const content = messageContents[index];
if (content !== undefined) {
const newParsedContent = messageParser.parse(message.id, content);
setParsedMessages((prevParsed) => ({
...prevParsed,
[index]: !reset ? (prevParsed[index] || '') + newParsedContent : newParsedContent,
}));
}
}
}
}, []);
return { parsedMessages, parseMessages };

View File

@ -7,7 +7,7 @@ import SwitchableStream from '~/lib/.server/llm/switchable-stream';
import type { IProviderSetting } from '~/types/model';
import { createScopedLogger } from '~/utils/logger';
import { getFilePaths, selectContext } from '~/lib/.server/llm/select-context';
import type { ContextAnnotation, ProgressAnnotation } from '~/types/context';
import type { ContextAnnotation, ProgressAnnotation, SegmentsGroupAnnotation } from '~/types/context';
import { WORK_DIR } from '~/utils/constants';
import { createSummary } from '~/lib/.server/llm/create-summary';
import { extractPropertiesFromMessage } from '~/lib/.server/llm/utils';
@ -59,6 +59,7 @@ async function chatAction({ context, request }: ActionFunctionArgs) {
);
const stream = new SwitchableStream();
const segmentsGroupId = generateId();
const cumulativeUsage = {
completionTokens: 0,
@ -238,6 +239,11 @@ async function chatAction({ context, request }: ActionFunctionArgs) {
content: `[Model: ${model}]\n\n[Provider: ${provider}]\n\n${CONTINUE_PROMPT}`,
});
dataStream.writeMessageAnnotation({
type: 'segmentsGroup',
segmentsGroupId,
} satisfies SegmentsGroupAnnotation);
const result = await streamText({
messages,
env: context.cloudflare?.env,

View File

@ -16,3 +16,8 @@ export type ProgressAnnotation = {
order: number;
message: string;
};
export type SegmentsGroupAnnotation = {
type: 'segmentsGroup';
segmentsGroupId: string;
};