@@ -3,6 +3,7 @@ import { getModel } from '~/lib/.server/llm/model';
33import { MAX_TOKENS } from './constants' ;
44import { getSystemPrompt } from './prompts' ;
55import { DEFAULT_MODEL , DEFAULT_PROVIDER , getModelList , MODEL_REGEX , PROVIDER_REGEX } from '~/utils/constants' ;
6+ import ignore from 'ignore' ;
67import type { IProviderSetting } from '~/types/model' ;
78
89interface ToolResult < Name extends string , Args , Result > {
@@ -23,6 +24,78 @@ export type Messages = Message[];
2324
2425export type StreamingOptions = Omit < Parameters < typeof _streamText > [ 0 ] , 'model' > ;
2526
27+ export interface File {
28+ type : 'file' ;
29+ content : string ;
30+ isBinary : boolean ;
31+ }
32+
33+ export interface Folder {
34+ type : 'folder' ;
35+ }
36+
37+ type Dirent = File | Folder ;
38+
39+ export type FileMap = Record < string , Dirent | undefined > ;
40+
41+ function simplifyBoltActions ( input : string ) : string {
42+ // Using regex to match boltAction tags that have type="file"
43+ const regex = / ( < b o l t A c t i o n [ ^ > ] * t y p e = " f i l e " [ ^ > ] * > ) ( [ \s \S ] * ?) ( < \/ b o l t A c t i o n > ) / g;
44+
45+ // Replace each matching occurrence
46+ return input . replace ( regex , ( _0 , openingTag , _2 , closingTag ) => {
47+ return `${ openingTag } \n ...\n ${ closingTag } ` ;
48+ } ) ;
49+ }
50+
51+ // Common patterns to ignore, similar to .gitignore
52+ const IGNORE_PATTERNS = [
53+ 'node_modules/**' ,
54+ '.git/**' ,
55+ 'dist/**' ,
56+ 'build/**' ,
57+ '.next/**' ,
58+ 'coverage/**' ,
59+ '.cache/**' ,
60+ '.vscode/**' ,
61+ '.idea/**' ,
62+ '**/*.log' ,
63+ '**/.DS_Store' ,
64+ '**/npm-debug.log*' ,
65+ '**/yarn-debug.log*' ,
66+ '**/yarn-error.log*' ,
67+ '**/*lock.json' ,
68+ '**/*lock.yml' ,
69+ ] ;
70+ const ig = ignore ( ) . add ( IGNORE_PATTERNS ) ;
71+
72+ function createFilesContext ( files : FileMap ) {
73+ let filePaths = Object . keys ( files ) ;
74+ filePaths = filePaths . filter ( ( x ) => {
75+ const relPath = x . replace ( '/home/project/' , '' ) ;
76+ return ! ig . ignores ( relPath ) ;
77+ } ) ;
78+
79+ const fileContexts = filePaths
80+ . filter ( ( x ) => files [ x ] && files [ x ] . type == 'file' )
81+ . map ( ( path ) => {
82+ const dirent = files [ path ] ;
83+
84+ if ( ! dirent || dirent . type == 'folder' ) {
85+ return '' ;
86+ }
87+
88+ const codeWithLinesNumbers = dirent . content
89+ . split ( '\n' )
90+ . map ( ( v , i ) => `${ i + 1 } |${ v } ` )
91+ . join ( '\n' ) ;
92+
93+ return `<file path="${ path } ">\n${ codeWithLinesNumbers } \n</file>` ;
94+ } ) ;
95+
96+ return `Below are the code files present in the webcontainer:\ncode format:\n<line number>|<line content>\n <codebase>${ fileContexts . join ( '\n\n' ) } \n\n</codebase>` ;
97+ }
98+
2699function extractPropertiesFromMessage ( message : Message ) : { model : string ; provider : string ; content : string } {
27100 const textContent = Array . isArray ( message . content )
28101 ? message . content . find ( ( item ) => item . type === 'text' ) ?. text || ''
@@ -64,9 +137,10 @@ export async function streamText(props: {
64137 env : Env ;
65138 options ?: StreamingOptions ;
66139 apiKeys ?: Record < string , string > ;
140+ files ?: FileMap ;
67141 providerSettings ?: Record < string , IProviderSetting > ;
68142} ) {
69- const { messages, env, options, apiKeys, providerSettings } = props ;
143+ const { messages, env, options, apiKeys, files , providerSettings } = props ;
70144 let currentModel = DEFAULT_MODEL ;
71145 let currentProvider = DEFAULT_PROVIDER . name ;
72146 const MODEL_LIST = await getModelList ( apiKeys || { } , providerSettings ) ;
@@ -80,6 +154,11 @@ export async function streamText(props: {
80154
81155 currentProvider = provider ;
82156
157+ return { ...message , content } ;
158+ } else if ( message . role == 'assistant' ) {
159+ let content = message . content ;
160+ content = simplifyBoltActions ( content ) ;
161+
83162 return { ...message , content } ;
84163 }
85164
@@ -90,9 +169,17 @@ export async function streamText(props: {
90169
91170 const dynamicMaxTokens = modelDetails && modelDetails . maxTokenAllowed ? modelDetails . maxTokenAllowed : MAX_TOKENS ;
92171
172+ let systemPrompt = getSystemPrompt ( ) ;
173+ let codeContext = '' ;
174+
175+ if ( files ) {
176+ codeContext = createFilesContext ( files ) ;
177+ systemPrompt = `${ systemPrompt } \n\n ${ codeContext } ` ;
178+ }
179+
93180 return _streamText ( {
94181 model : getModel ( currentProvider , currentModel , env , apiKeys , providerSettings ) as any ,
95- system : getSystemPrompt ( ) ,
182+ system : systemPrompt ,
96183 maxTokens : dynamicMaxTokens ,
97184 messages : convertToCoreMessages ( processedMessages as any ) ,
98185 ...options ,
0 commit comments