mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 10:16:01 +00:00
fix: fix prompt continuation
This commit is contained in:
parent
f0aa58c922
commit
3e1bcb9849
@ -531,7 +531,9 @@ export const ChatImpl = memo(
|
|||||||
description={description}
|
description={description}
|
||||||
importChat={importChat}
|
importChat={importChat}
|
||||||
exportChat={exportChat}
|
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') {
|
if (message.role === 'user') {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { WORK_DIR } from '~/utils/constants';
|
import { WORK_DIR } from '~/utils/constants';
|
||||||
import { allowedHTMLElements } from '~/utils/markdown';
|
import { allowedHTMLElements } from '~/utils/markdown';
|
||||||
import { stripIndents } from '~/utils/stripIndent';
|
|
||||||
|
|
||||||
export const getFineTunedPrompt = (
|
export const getFineTunedPrompt = (
|
||||||
cwd: string = WORK_DIR,
|
cwd: string = WORK_DIR,
|
||||||
@ -695,7 +694,12 @@ npm run dev
|
|||||||
</example>
|
</example>
|
||||||
</examples>`;
|
</examples>`;
|
||||||
|
|
||||||
export const CONTINUE_PROMPT = stripIndents`
|
export const CONTINUE_PROMPT = `Continue your prior response.
|
||||||
Continue your prior response. IMPORTANT: Immediately begin from where you left off without any interruptions.
|
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.
|
||||||
Do not repeat any content, including artifact and action tags.
|
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>`;
|
||||||
|
@ -698,7 +698,12 @@ Here are some examples of correct usage of artifacts:
|
|||||||
</examples>
|
</examples>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CONTINUE_PROMPT = stripIndents`
|
export const CONTINUE_PROMPT = `Continue your prior response.
|
||||||
Continue your prior response. IMPORTANT: Immediately begin from where you left off without any interruptions.
|
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.
|
||||||
Do not repeat any content, including artifact and action tags.
|
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>`;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import type { Message } from 'ai';
|
import type { JSONValue, Message } from 'ai';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { StreamingMessageParser } from '~/lib/runtime/message-parser';
|
import { StreamingMessageParser } from '~/lib/runtime/message-parser';
|
||||||
import { workbenchStore } from '~/lib/stores/workbench';
|
import { workbenchStore } from '~/lib/stores/workbench';
|
||||||
|
import type { SegmentsGroupAnnotation } from '~/types/context';
|
||||||
import { createScopedLogger } from '~/utils/logger';
|
import { createScopedLogger } from '~/utils/logger';
|
||||||
|
|
||||||
const logger = createScopedLogger('useMessageParser');
|
const logger = createScopedLogger('useMessageParser');
|
||||||
@ -47,6 +48,14 @@ const extractTextContent = (message: Message) =>
|
|||||||
? (message.content.find((item) => item.type === 'text')?.text as string) || ''
|
? (message.content.find((item) => item.type === 'text')?.text as string) || ''
|
||||||
: message.content;
|
: 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() {
|
export function useMessageParser() {
|
||||||
const [parsedMessages, setParsedMessages] = useState<{ [key: number]: string }>({});
|
const [parsedMessages, setParsedMessages] = useState<{ [key: number]: string }>({});
|
||||||
|
|
||||||
@ -58,15 +67,46 @@ export function useMessageParser() {
|
|||||||
messageParser.reset();
|
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()) {
|
for (const [index, message] of messages.entries()) {
|
||||||
if (message.role === 'assistant' || message.role === 'user') {
|
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) => ({
|
setParsedMessages((prevParsed) => ({
|
||||||
...prevParsed,
|
...prevParsed,
|
||||||
[index]: !reset ? (prevParsed[index] || '') + newParsedContent : newParsedContent,
|
[index]: !reset ? (prevParsed[index] || '') + newParsedContent : newParsedContent,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return { parsedMessages, parseMessages };
|
return { parsedMessages, parseMessages };
|
||||||
|
@ -7,7 +7,7 @@ import SwitchableStream from '~/lib/.server/llm/switchable-stream';
|
|||||||
import type { IProviderSetting } from '~/types/model';
|
import type { IProviderSetting } from '~/types/model';
|
||||||
import { createScopedLogger } from '~/utils/logger';
|
import { createScopedLogger } from '~/utils/logger';
|
||||||
import { getFilePaths, selectContext } from '~/lib/.server/llm/select-context';
|
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 { WORK_DIR } from '~/utils/constants';
|
||||||
import { createSummary } from '~/lib/.server/llm/create-summary';
|
import { createSummary } from '~/lib/.server/llm/create-summary';
|
||||||
import { extractPropertiesFromMessage } from '~/lib/.server/llm/utils';
|
import { extractPropertiesFromMessage } from '~/lib/.server/llm/utils';
|
||||||
@ -59,6 +59,7 @@ async function chatAction({ context, request }: ActionFunctionArgs) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const stream = new SwitchableStream();
|
const stream = new SwitchableStream();
|
||||||
|
const segmentsGroupId = generateId();
|
||||||
|
|
||||||
const cumulativeUsage = {
|
const cumulativeUsage = {
|
||||||
completionTokens: 0,
|
completionTokens: 0,
|
||||||
@ -238,6 +239,11 @@ async function chatAction({ context, request }: ActionFunctionArgs) {
|
|||||||
content: `[Model: ${model}]\n\n[Provider: ${provider}]\n\n${CONTINUE_PROMPT}`,
|
content: `[Model: ${model}]\n\n[Provider: ${provider}]\n\n${CONTINUE_PROMPT}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dataStream.writeMessageAnnotation({
|
||||||
|
type: 'segmentsGroup',
|
||||||
|
segmentsGroupId,
|
||||||
|
} satisfies SegmentsGroupAnnotation);
|
||||||
|
|
||||||
const result = await streamText({
|
const result = await streamText({
|
||||||
messages,
|
messages,
|
||||||
env: context.cloudflare?.env,
|
env: context.cloudflare?.env,
|
||||||
|
@ -16,3 +16,8 @@ export type ProgressAnnotation = {
|
|||||||
order: number;
|
order: number;
|
||||||
message: string;
|
message: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type SegmentsGroupAnnotation = {
|
||||||
|
type: 'segmentsGroup';
|
||||||
|
segmentsGroupId: string;
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user