-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Issue#186 #1121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Issue#186 #1121
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -71,6 +71,36 @@ export class StagehandActHandler { | |||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
const method = observe.method; | ||||||||||||||||||||||||||||||
const args = Array.isArray(observe.arguments) ? [...observe.arguments] : []; | ||||||||||||||||||||||||||||||
const selector = | ||||||||||||||||||||||||||||||
this.normalizeSelector(observe.selector) ?? observe.selector; | ||||||||||||||||||||||||||||||
let attemptedPlaywrightCommand = this.buildPlaywrightCommand( | ||||||||||||||||||||||||||||||
method, | ||||||||||||||||||||||||||||||
args, | ||||||||||||||||||||||||||||||
selector, | ||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
if (!method) { | ||||||||||||||||||||||||||||||
this.logger({ | ||||||||||||||||||||||||||||||
category: "action", | ||||||||||||||||||||||||||||||
message: "ObserveResult did not include a Playwright method", | ||||||||||||||||||||||||||||||
level: 1, | ||||||||||||||||||||||||||||||
auxiliary: { | ||||||||||||||||||||||||||||||
observeResult: { | ||||||||||||||||||||||||||||||
value: JSON.stringify(observe), | ||||||||||||||||||||||||||||||
type: "object", | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||
success: false, | ||||||||||||||||||||||||||||||
message: | ||||||||||||||||||||||||||||||
"Unable to perform action: The ObserveResult did not include a Playwright method.", | ||||||||||||||||||||||||||||||
action: observe.description || "ObserveResult action", | ||||||||||||||||||||||||||||||
playwrightCommand: attemptedPlaywrightCommand, | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
if (method === "not-supported") { | ||||||||||||||||||||||||||||||
this.logger({ | ||||||||||||||||||||||||||||||
category: "action", | ||||||||||||||||||||||||||||||
|
@@ -92,11 +122,9 @@ export class StagehandActHandler { | |||||||||||||||||||||||||||||
success: false, | ||||||||||||||||||||||||||||||
message: `Unable to perform action: The method '${method}' is not supported in ObserveResult. Please use a supported Playwright locator method.`, | ||||||||||||||||||||||||||||||
action: observe.description || `ObserveResult action (${method})`, | ||||||||||||||||||||||||||||||
playwrightCommand: attemptedPlaywrightCommand, | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
const args = observe.arguments ?? []; | ||||||||||||||||||||||||||||||
// remove the xpath prefix on the selector | ||||||||||||||||||||||||||||||
const selector = observe.selector.replace("xpath=", ""); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||
await this._performPlaywrightMethod( | ||||||||||||||||||||||||||||||
|
@@ -110,6 +138,7 @@ export class StagehandActHandler { | |||||||||||||||||||||||||||||
success: true, | ||||||||||||||||||||||||||||||
message: `Action [${method}] performed successfully on selector: ${selector}`, | ||||||||||||||||||||||||||||||
action: observe.description || `ObserveResult action (${method})`, | ||||||||||||||||||||||||||||||
playwrightCommand: attemptedPlaywrightCommand, | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
} catch (err) { | ||||||||||||||||||||||||||||||
if ( | ||||||||||||||||||||||||||||||
|
@@ -129,6 +158,7 @@ export class StagehandActHandler { | |||||||||||||||||||||||||||||
success: false, | ||||||||||||||||||||||||||||||
message: `Failed to perform act: ${err.message}`, | ||||||||||||||||||||||||||||||
action: observe.description || `ObserveResult action (${method})`, | ||||||||||||||||||||||||||||||
playwrightCommand: attemptedPlaywrightCommand, | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
// We will try to use observeAct on a failed ObserveResult-act if selfHeal is true | ||||||||||||||||||||||||||||||
|
@@ -165,21 +195,30 @@ export class StagehandActHandler { | |||||||||||||||||||||||||||||
success: false, | ||||||||||||||||||||||||||||||
message: `Failed to self heal act: Element not found.`, | ||||||||||||||||||||||||||||||
action: actCommand, | ||||||||||||||||||||||||||||||
playwrightCommand: attemptedPlaywrightCommand, | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
const element: ObserveResult = observeResults[0]; | ||||||||||||||||||||||||||||||
const fallbackSelector = | ||||||||||||||||||||||||||||||
this.normalizeSelector(element.selector) ?? element.selector; | ||||||||||||||||||||||||||||||
attemptedPlaywrightCommand = this.buildPlaywrightCommand( | ||||||||||||||||||||||||||||||
observe.method, | ||||||||||||||||||||||||||||||
observe.arguments, | ||||||||||||||||||||||||||||||
fallbackSelector, | ||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||
await this._performPlaywrightMethod( | ||||||||||||||||||||||||||||||
// override previously provided method and arguments | ||||||||||||||||||||||||||||||
observe.method, | ||||||||||||||||||||||||||||||
observe.arguments, | ||||||||||||||||||||||||||||||
// only update selector | ||||||||||||||||||||||||||||||
element.selector, | ||||||||||||||||||||||||||||||
fallbackSelector, | ||||||||||||||||||||||||||||||
domSettleTimeoutMs, | ||||||||||||||||||||||||||||||
Comment on lines
209
to
215
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: self-heal uses original method/args instead of new element's the comment says "override previously provided method and arguments" but the code does the opposite - it uses the original
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: lib/handlers/actHandler.ts
Line: 209:215
Comment:
**logic:** self-heal uses original method/args instead of new element's
the comment says "override previously provided method and arguments" but the code does the opposite - it uses the original `observe.method` and `observe.arguments` instead of using the new `element.method` and `element.arguments` from the fresh observation
```suggestion
await this._performPlaywrightMethod(
element.method,
element.arguments,
fallbackSelector,
domSettleTimeoutMs,
);
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||
success: true, | ||||||||||||||||||||||||||||||
message: `Action [${element.method}] performed successfully on selector: ${element.selector}`, | ||||||||||||||||||||||||||||||
action: observe.description || `ObserveResult action (${method})`, | ||||||||||||||||||||||||||||||
playwrightCommand: attemptedPlaywrightCommand, | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
} catch (err) { | ||||||||||||||||||||||||||||||
this.logger({ | ||||||||||||||||||||||||||||||
|
@@ -195,11 +234,38 @@ export class StagehandActHandler { | |||||||||||||||||||||||||||||
success: false, | ||||||||||||||||||||||||||||||
message: `Failed to perform act: ${err.message}`, | ||||||||||||||||||||||||||||||
action: observe.description || `ObserveResult action (${method})`, | ||||||||||||||||||||||||||||||
playwrightCommand: attemptedPlaywrightCommand, | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
private normalizeSelector(selector?: string): string | undefined { | ||||||||||||||||||||||||||||||
if (!selector) { | ||||||||||||||||||||||||||||||
return undefined; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
return selector.replace(/^xpath=/i, "").trim(); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
private buildPlaywrightCommand( | ||||||||||||||||||||||||||||||
method: string | undefined, | ||||||||||||||||||||||||||||||
args: unknown[] | undefined, | ||||||||||||||||||||||||||||||
selector: string | undefined, | ||||||||||||||||||||||||||||||
): ActResult["playwrightCommand"] { | ||||||||||||||||||||||||||||||
if (!method || !selector) { | ||||||||||||||||||||||||||||||
return undefined; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
const commandArguments = Array.isArray(args) ? args : []; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||
method, | ||||||||||||||||||||||||||||||
selector, | ||||||||||||||||||||||||||||||
arguments: commandArguments, | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||
* Perform an act based on an instruction. | ||||||||||||||||||||||||||||||
* This method will observe the page and then perform the act on the first element returned. | ||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: self-heal fallback uses wrong method/args
uses
observe.method
andobserve.arguments
(from original failed attempt) instead ofelement.method
andelement.arguments
from the newly observed elementPrompt To Fix With AI