forked from stackblitz-labs/bolt.diy
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: enhance context handling by adding code context selection and i…
…mplementing summary generation (stackblitz-labs#1091) #release * feat: add context annotation types and enhance file handling in LLM processing * feat: enhance context handling by adding chatId to annotations and implementing summary generation * removed useless changes * feat: updated token counts to include optimization requests * prompt fix * logging added * useless logs removed
- Loading branch information
1 parent
2ae897a
commit 3c56346
Showing
16 changed files
with
1,154 additions
and
223 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import * as Popover from '@radix-ui/react-popover'; | ||
import type { PropsWithChildren, ReactNode } from 'react'; | ||
|
||
export default ({ children, trigger }: PropsWithChildren<{ trigger: ReactNode }>) => ( | ||
<Popover.Root> | ||
<Popover.Trigger asChild>{trigger}</Popover.Trigger> | ||
<Popover.Anchor /> | ||
<Popover.Portal> | ||
<Popover.Content | ||
sideOffset={10} | ||
side="top" | ||
align="center" | ||
className="bg-bolt-elements-background-depth-2 text-bolt-elements-item-contentAccent p-2 rounded-md shadow-xl z-workbench" | ||
> | ||
{children} | ||
<Popover.Arrow className="bg-bolt-elements-item-background-depth-2" /> | ||
</Popover.Content> | ||
</Popover.Portal> | ||
</Popover.Root> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import { generateText, type CoreTool, type GenerateTextResult, type Message } from 'ai'; | ||
import type { IProviderSetting } from '~/types/model'; | ||
import { DEFAULT_MODEL, DEFAULT_PROVIDER, PROVIDER_LIST } from '~/utils/constants'; | ||
import { extractCurrentContext, extractPropertiesFromMessage, simplifyBoltActions } from './utils'; | ||
import { createScopedLogger } from '~/utils/logger'; | ||
import { LLMManager } from '~/lib/modules/llm/manager'; | ||
|
||
const logger = createScopedLogger('create-summary'); | ||
|
||
export async function createSummary(props: { | ||
messages: Message[]; | ||
env?: Env; | ||
apiKeys?: Record<string, string>; | ||
providerSettings?: Record<string, IProviderSetting>; | ||
promptId?: string; | ||
contextOptimization?: boolean; | ||
onFinish?: (resp: GenerateTextResult<Record<string, CoreTool<any, any>>, never>) => void; | ||
}) { | ||
const { messages, env: serverEnv, apiKeys, providerSettings, contextOptimization, onFinish } = props; | ||
let currentModel = DEFAULT_MODEL; | ||
let currentProvider = DEFAULT_PROVIDER.name; | ||
const processedMessages = messages.map((message) => { | ||
if (message.role === 'user') { | ||
const { model, provider, content } = extractPropertiesFromMessage(message); | ||
currentModel = model; | ||
currentProvider = provider; | ||
|
||
return { ...message, content }; | ||
} else if (message.role == 'assistant') { | ||
let content = message.content; | ||
|
||
if (contextOptimization) { | ||
content = simplifyBoltActions(content); | ||
} | ||
|
||
return { ...message, content }; | ||
} | ||
|
||
return message; | ||
}); | ||
|
||
const provider = PROVIDER_LIST.find((p) => p.name === currentProvider) || DEFAULT_PROVIDER; | ||
const staticModels = LLMManager.getInstance().getStaticModelListFromProvider(provider); | ||
let modelDetails = staticModels.find((m) => m.name === currentModel); | ||
|
||
if (!modelDetails) { | ||
const modelsList = [ | ||
...(provider.staticModels || []), | ||
...(await LLMManager.getInstance().getModelListFromProvider(provider, { | ||
apiKeys, | ||
providerSettings, | ||
serverEnv: serverEnv as any, | ||
})), | ||
]; | ||
|
||
if (!modelsList.length) { | ||
throw new Error(`No models found for provider ${provider.name}`); | ||
} | ||
|
||
modelDetails = modelsList.find((m) => m.name === currentModel); | ||
|
||
if (!modelDetails) { | ||
// Fallback to first model | ||
logger.warn( | ||
`MODEL [${currentModel}] not found in provider [${provider.name}]. Falling back to first model. ${modelsList[0].name}`, | ||
); | ||
modelDetails = modelsList[0]; | ||
} | ||
} | ||
|
||
let slicedMessages = processedMessages; | ||
const { summary } = extractCurrentContext(processedMessages); | ||
let summaryText: string | undefined = undefined; | ||
let chatId: string | undefined = undefined; | ||
|
||
if (summary && summary.type === 'chatSummary') { | ||
chatId = summary.chatId; | ||
summaryText = `Below is the Chat Summary till now, this is chat summary before the conversation provided by the user | ||
you should also use this as historical message while providing the response to the user. | ||
${summary.summary}`; | ||
|
||
if (chatId) { | ||
let index = 0; | ||
|
||
for (let i = 0; i < processedMessages.length; i++) { | ||
if (processedMessages[i].id === chatId) { | ||
index = i; | ||
break; | ||
} | ||
} | ||
slicedMessages = processedMessages.slice(index + 1); | ||
} | ||
} | ||
|
||
const extractTextContent = (message: Message) => | ||
Array.isArray(message.content) | ||
? (message.content.find((item) => item.type === 'text')?.text as string) || '' | ||
: message.content; | ||
|
||
// select files from the list of code file from the project that might be useful for the current request from the user | ||
const resp = await generateText({ | ||
system: ` | ||
You are a software engineer. You are working on a project. tou need to summarize the work till now and provide a summary of the chat till now. | ||
${summaryText} | ||
RULES: | ||
* Only provide the summary of the chat till now. | ||
* Do not provide any new information. | ||
`, | ||
prompt: ` | ||
please provide a summary of the chat till now. | ||
below is the latest chat: | ||
--- | ||
${slicedMessages | ||
.map((x) => { | ||
return `---\n[${x.role}] ${extractTextContent(x)}\n---`; | ||
}) | ||
.join('\n')} | ||
--- | ||
`, | ||
model: provider.getModelInstance({ | ||
model: currentModel, | ||
serverEnv, | ||
apiKeys, | ||
providerSettings, | ||
}), | ||
}); | ||
|
||
const response = resp.text; | ||
|
||
if (onFinish) { | ||
onFinish(resp); | ||
} | ||
|
||
return response; | ||
} |
Oops, something went wrong.