55import * as Host from '../../../core/host/host.js' ;
66import * as TextUtils from '../../../models/text_utils/text_utils.js' ;
77import type * as Workspace from '../../../models/workspace/workspace.js' ;
8- import type * as Lit from '../../../ui/lit/lit .js' ;
8+ import { debugLog } from '../debug .js' ;
99
1010import {
1111 type AgentOptions as BaseAgentOptions ,
1212 AgentType ,
1313 AiAgent ,
1414 type ContextResponse ,
15- ConversationContext ,
15+ type ConversationContext ,
1616 type RequestOptions ,
1717 type ResponseData ,
18+ ResponseType ,
1819} from './AiAgent.js' ;
1920
20- export class ProjectContext extends ConversationContext < Workspace . Workspace . Project > {
21- readonly #project: Workspace . Workspace . Project ;
22-
23- constructor ( project : Workspace . Workspace . Project ) {
24- super ( ) ;
25- this . #project = project ;
26- }
27-
28- getOrigin ( ) : string {
29- // TODO
30- return 'test' ;
31- }
32-
33- getItem ( ) : Workspace . Workspace . Project {
34- return this . #project;
35- }
36-
37- override getIcon ( ) : HTMLElement {
38- return document . createElement ( 'span' ) ;
39- }
40-
41- override getTitle ( ) : string | ReturnType < typeof Lit . Directives . until > {
42- return this . #project. displayName ( ) ;
43- }
44- }
45-
4621function getFiles ( project : Workspace . Workspace . Project ) :
4722 { files : string [ ] , map : Map < string , Workspace . UISourceCode . UISourceCode > } {
4823 const files = [ ] ;
@@ -60,13 +35,14 @@ function getFiles(project: Workspace.Workspace.Project):
6035}
6136
6237export class PatchAgent extends AiAgent < Workspace . Workspace . Project > {
63- #project: ConversationContext < Workspace . Workspace . Project > | undefined ;
38+ #project: Workspace . Workspace . Project ;
39+ #fileUpdateAgent: FileUpdateAgent ;
40+ #changeSummary = '' ;
6441
6542 override async *
6643 // eslint-disable-next-line require-yield
6744 handleContextDetails ( _select : ConversationContext < Workspace . Workspace . Project > | null ) :
6845 AsyncGenerator < ContextResponse , void , void > {
69- // TODO: Implement
7046 return ;
7147 }
7248
@@ -85,8 +61,10 @@ export class PatchAgent extends AiAgent<Workspace.Workspace.Project> {
8561 } ;
8662 }
8763
88- constructor ( opts : BaseAgentOptions ) {
64+ constructor ( opts : BaseAgentOptions & { fileUpdateAgent ?: FileUpdateAgent , project : Workspace . Workspace . Project } ) {
8965 super ( opts ) ;
66+ this . #project = opts . project ;
67+ this . #fileUpdateAgent = opts . fileUpdateAgent ?? new FileUpdateAgent ( opts ) ;
9068 this . declareFunction < Record < never , unknown > > ( 'listFiles' , {
9169 description : 'Returns a list of all files in the project.' ,
9270 parameters : {
@@ -101,7 +79,7 @@ export class PatchAgent extends AiAgent<Workspace.Workspace.Project> {
10179 error : 'No project available' ,
10280 } ;
10381 }
104- const project = this . #project. getItem ( ) ;
82+ const project = this . #project;
10583 const { files} = getFiles ( project ) ;
10684 return {
10785 result : {
@@ -146,13 +124,17 @@ export class PatchAgent extends AiAgent<Workspace.Workspace.Project> {
146124 error : 'No project available' ,
147125 } ;
148126 }
149- const project = this . #project. getItem ( ) ;
127+ const project = this . #project;
150128 const { map} = getFiles ( project ) ;
151129 const matches = [ ] ;
152130 for ( const [ filepath , file ] of map . entries ( ) ) {
131+ await file . requestContentData ( ) ;
132+ debugLog ( 'searching in' , filepath , 'for' , params . query ) ;
133+ const content = file . isDirty ( ) ? file . workingCopyContentData ( ) : await file . requestContentData ( ) ;
153134 const results = TextUtils . TextUtils . performSearchInContentData (
154- file . workingCopyContentData ( ) , params . query , params . caseSensitive ?? true , params . isRegex ?? false ) ;
135+ content , params . query , params . caseSensitive ?? true , params . isRegex ?? false ) ;
155136 for ( const result of results ) {
137+ debugLog ( 'matches in' , filepath ) ;
156138 matches . push ( {
157139 filepath,
158140 lineNumber : result . lineNumber ,
@@ -168,13 +150,116 @@ export class PatchAgent extends AiAgent<Workspace.Workspace.Project> {
168150 } ;
169151 } ,
170152 } ) ;
153+
154+ this . declareFunction < {
155+ files : string [ ] ,
156+ } > ( 'updateFiles' , {
157+ description : 'When called this function performs necesary updates to files' ,
158+ parameters : {
159+ type : Host . AidaClient . ParametersTypes . OBJECT ,
160+ description : '' ,
161+ nullable : false ,
162+ properties : {
163+ files : {
164+ type : Host . AidaClient . ParametersTypes . ARRAY ,
165+ description : 'List of file names from the project' ,
166+ nullable : false ,
167+ items : { type : Host . AidaClient . ParametersTypes . STRING , description : 'File name' }
168+ }
169+ } ,
170+ } ,
171+ handler : async args => {
172+ debugLog ( 'updateFiles' , args . files ) ;
173+ if ( ! this . #project) {
174+ return {
175+ error : 'No project available' ,
176+ } ;
177+ }
178+ const project = this . #project;
179+ const { map} = getFiles ( project ) ;
180+ for ( const file of args . files . slice ( 0 , 3 ) ) {
181+ debugLog ( 'updating' , file ) ;
182+ const uiSourceCode = map . get ( file ) ;
183+ if ( ! uiSourceCode ) {
184+ debugLog ( file , 'not found' ) ;
185+ continue ;
186+ }
187+ const prompt = `I have applied the following CSS changes to my page in Chrome DevTools.
188+
189+ \`\`\`css
190+ ${ this . #changeSummary}
191+ \`\`\`
192+
193+ Following '===' I provide the source code file. Update the file to apply the same change to it.
194+ CRITICAL: Output the entire file with changes without any other modifications! DO NOT USE MARKDOWN.
195+
196+ ===
197+ ${ uiSourceCode . workingCopyContentData ( ) . text }
198+ ` ;
199+ let response ;
200+ for await ( response of this . #fileUpdateAgent. run ( prompt , { selected : null } ) ) {
201+ }
202+ debugLog ( 'response' , response ) ;
203+ if ( response ?. type !== ResponseType . ANSWER ) {
204+ debugLog ( 'wrong response type' , response ) ;
205+ continue ;
206+ }
207+ const updated = response . text ;
208+ uiSourceCode . setWorkingCopy ( updated ) ;
209+ debugLog ( 'updated' , updated ) ;
210+ }
211+ return {
212+ result : {
213+ success : true ,
214+ }
215+ } ;
216+ } ,
217+ } ) ;
218+ }
219+
220+ async * applyChanges ( changeSummary : string ) : AsyncGenerator < ResponseData , void , void > {
221+ this . #changeSummary = changeSummary ;
222+ const prompt =
223+ `I have applied the following CSS changes to my page in Chrome DevTools, what are the files in my source code that I need to change to apply the same change?
224+
225+ \`\`\`css
226+ ${ changeSummary }
227+ \`\`\`
228+
229+ Try searching using the selectors and if nothing matches, try to find a semantically appropriate place to change.
230+ Consider updating files containing styles like CSS files first!
231+ Call the updateFiles with the list of files to be updated once you are done.
232+ ` ;
233+
234+ yield * this . run ( prompt , {
235+ selected : null ,
236+ } ) ;
237+ }
238+ }
239+
240+ /**
241+ * This is an inner "agent" to apply a change to one file.
242+ */
243+ export class FileUpdateAgent extends AiAgent < Workspace . Workspace . Project > {
244+ override async *
245+ // eslint-disable-next-line require-yield
246+ handleContextDetails ( _select : ConversationContext < Workspace . Workspace . Project > | null ) :
247+ AsyncGenerator < ContextResponse , void , void > {
248+ return ;
171249 }
172250
173- override async * run ( initialQuery : string , options : {
174- signal ?: AbortSignal , selected : ConversationContext < Workspace . Workspace . Project > | null ,
175- } ) : AsyncGenerator < ResponseData , void , void > {
176- this . #project = options . selected ?? undefined ;
251+ override readonly type = AgentType . PATCH ;
252+ readonly preamble = undefined ;
253+ readonly clientFeature = Host . AidaClient . ClientFeature . CHROME_PATCH_AGENT ;
177254
178- return yield * super . run ( initialQuery , options ) ;
255+ get userTier ( ) : string | undefined {
256+ return 'TESTERS' ;
257+ }
258+
259+ get options ( ) : RequestOptions {
260+ return {
261+ temperature : undefined ,
262+ modelId : undefined ,
263+ } ;
179264 }
180265}
0 commit comments