Updates to make browser remote port dynamic from prompt

This commit is contained in:
a8trejo 2024-11-27 19:11:57 -08:00
parent 4763c4ecb7
commit b0e48c5489
3 changed files with 44 additions and 16 deletions

View file

@ -1,2 +1,4 @@
Could you navigate to this URL in interactive mode (isInteractive = true), and keep it open while I chat with you, DO NOT DO ANYTHING UNTIL I TELL YOU TO CONTINUE.
https://cloud.cypress.io/projects/hkawvm/runs/22055/overview/b890f243-ce56-4047-9252-c99469dfbbea?roarHideRunsWithDiffGroupsAndTags=1&interactive=true
Could you navigate to this URL in interactive mode (browserPort = 7333)
https://cloud.cypress.io/projects/hkawvm/runs/22055/overview/b890f243-ce56-4047-9252-c99469dfbbea?roarHideRunsWithDiffGroupsAndTags=1&interactive=true
Please analyze the failure and let me know if you can fix it.

View file

@ -74,6 +74,7 @@ export class Cline {
private browserSession: BrowserSession
private didEditFile: boolean = false
private isInteractiveMode: boolean = false
private browserPort: string = '7333'
customInstructions?: string
alwaysAllowReadOnly: boolean
alwaysAllowWrite: boolean
@ -669,16 +670,22 @@ export class Cline {
newUserContent.push(...formatResponse.imageBlocks(responseImages))
}
const wasInteractiveBrowser = (lastRelevantMessageIndex > 0) ? modifiedClineMessages[lastRelevantMessageIndex - 1].text?.includes("interactive mode") : false
let hadBrowserPort = '';
if ( wasInteractiveBrowser ) {
const match = modifiedClineMessages[lastRelevantMessageIndex - 1].text?.match(/\(browserPort\s*=\s*(\d+)\)/)
if (match) {
hadBrowserPort = match[1] ?? this.browserPort;
this.providerRef.deref()?.outputChannel.appendLine(`resumeTaskFromHistory :: browserPort :: ${hadBrowserPort}`)
}
}
await this.overwriteApiConversationHistory(modifiedApiConversationHistory)
await this.initiateTaskLoop(newUserContent, wasInteractiveBrowser)
await this.initiateTaskLoop(newUserContent, wasInteractiveBrowser, hadBrowserPort)
}
private async initiateTaskLoop(userContent: UserContent, wasInteractiveBrowser: boolean = false): Promise<void> {
private async initiateTaskLoop(userContent: UserContent, wasInteractiveBrowser: boolean = false, hadBrowserPort: string = ''): Promise<void> {
// Check if any text block contains "interactive mode"
const hasInteractiveMode = userContent.some((block) => {
if (block.type === "text" && typeof block.text === "string") {
this.providerRef.deref()?.outputChannel.appendLine(`initiateTaskLoop :: block.text :: ${block.text.toLowerCase()}`)
return (block.type === "text" &&
typeof block.text === "string" &&
block.text.toLowerCase().includes("interactive mode"))
@ -693,6 +700,17 @@ export class Cline {
// Set interactive mode flag if found in text
if (hasInteractiveMode) {
this.isInteractiveMode = true;
// Parse browserPort if specified in text blocks
userContent.forEach((block) => {
if (block.type === "text" && typeof block.text === "string") {
const match = block.text.match(/\(browserPort\s*=\s*(\d+)\)/)
if (match) {
this.browserPort = match[1] ?? hadBrowserPort;
this.providerRef.deref()?.outputChannel.appendLine(`initiateTaskLoop :: browserPort :: ${this.browserPort}`)
}
}
})
}
let nextUserContent = userContent;
@ -701,7 +719,8 @@ export class Cline {
const didEndLoop = await this.recursivelyMakeClineRequests(
nextUserContent,
includeFileDetails,
this.isInteractiveMode // Pass the flag to recursivelyMakeClineRequests
this.isInteractiveMode, // Pass the flag to recursivelyMakeClineRequests
this.browserPort // Pass the browserPort to recursivelyMakeClineRequests
)
includeFileDetails = false
@ -1493,7 +1512,7 @@ export class Cline {
// NOTE: it's okay that we call this message since the partial inspect_site is finished streaming. The only scenario we have to avoid is sending messages WHILE a partial message exists at the end of the messages array. For example the api_req_finished message would interfere with the partial message, so we needed to remove that.
// await this.say("inspect_site_result", "") // no result, starts the loading spinner waiting for result
await this.say("browser_action_result", "") // starts loading spinner
await this.browserSession.launchBrowser(this.isInteractiveMode)
await this.browserSession.launchBrowser(this.isInteractiveMode, this.browserPort)
browserActionResult = await this.browserSession.navigateToUrl(url)
} else {
if (action === "click") {
@ -1817,7 +1836,8 @@ export class Cline {
async recursivelyMakeClineRequests(
userContent: UserContent,
includeFileDetails: boolean = false,
isInteractiveMode: boolean = false
isInteractiveMode: boolean = false,
browserPort: string = '7333'
): Promise<boolean> {
if (this.abort) {
throw new Error("Cline instance aborted")
@ -2074,7 +2094,7 @@ export class Cline {
this.consecutiveMistakeCount++
}
const recDidEndLoop = await this.recursivelyMakeClineRequests(this.userMessageContent, false, this.isInteractiveMode)
const recDidEndLoop = await this.recursivelyMakeClineRequests(this.userMessageContent, false, this.isInteractiveMode, browserPort)
didEndLoop = recDidEndLoop
} else {
// if there's no assistant_responses, that means we got no text or tool_use content blocks from API which we should assume is an error

View file

@ -13,15 +13,21 @@ export class BrowserSession {
private page?: Page
private currentMousePosition?: string
private isInteractive: boolean = false
private browserPort: string = '7333'
constructor(context: vscode.ExtensionContext) {
this.context = context
}
async launchBrowser(interactive: boolean = false) {
async launchBrowser(interactive: boolean = false, port?: string) {
console.log("launch browser called")
this.isInteractive = interactive
// Set browserPort if provided, otherwise use default
if (port) {
this.browserPort = port
}
if (this.browser) {
await this.closeBrowser() // this may happen when the model launches a browser again after having used it already before
}
@ -29,20 +35,20 @@ export class BrowserSession {
if (this.isInteractive) {
try {
// Fetch the WebSocket endpoint from Chrome's debugging API
const response = await fetch('http://127.0.0.1:7333/json/version')
const response = await fetch(`http://127.0.0.1:${this.browserPort}/json/version`)
const data = await response.json()
const browserWSEndpoint = data.webSocketDebuggerUrl
if (!browserWSEndpoint) {
throw new Error('Could not get WebSocket endpoint from Chrome debugging API')
throw new Error(`BrowserSession.ts :: launchBrowser :: Could not get webSocketDebuggerUrl from Chrome debugging API, port: ${this.browserPort}`)
}
this.browser = await connect({
browserWSEndpoint,
})
} catch (error) {
console.error("Failed to connect to browser:", error)
throw new Error(`Failed to connect to browser: ${error.message}`)
console.error("BrowserSession.ts :: launchBrowser :: Failed to connect to browser, make sure you have a running browser with --remote-debugging-port=7333", error)
throw new Error(`BrowserSession.ts :: launchBrowser :: Failed to connect to browser: ${error.message}, make sure you have a running browser with --remote-debugging-port=7333`)
}
} else {
this.browser = await launch({
@ -63,7 +69,7 @@ export class BrowserSession {
return {
screenshot: "",
logs: this.isInteractive ?
"Browser launched in interactive mode. Please confirm when you're done using the browser." :
"Connected to browser in remote debugging mode." :
"Browser launched successfully.",
currentUrl: this.page?.url(),
currentMousePosition: this.currentMousePosition,