Skip to content

Fix: Pass variables to buildActPrompt during self-heal#1537

Open
kernel-systems-bot wants to merge 1 commit intobrowserbase:mainfrom
kernel-systems-bot:kernel-systems-bot/self-heal-variables
Open

Fix: Pass variables to buildActPrompt during self-heal#1537
kernel-systems-bot wants to merge 1 commit intobrowserbase:mainfrom
kernel-systems-bot:kernel-systems-bot/self-heal-variables

Conversation

@kernel-systems-bot
Copy link
Contributor

@kernel-systems-bot kernel-systems-bot commented Jan 14, 2026

Fix: Self-Heal Loop Uses Empty Variables Object

Summary

Fixes the self-heal retry path in actHandler.ts to pass variables instead of an empty object {} to buildActPrompt. This ensures the LLM knows about available variable placeholders during self-heal attempts.

Problem

In actHandler.ts, when an action fails and self-heal is triggered, the retry call to buildActPrompt was passing an empty object {} instead of the variables parameter that's available in scope:

// BEFORE (bug):
const instruction = buildActPrompt(
  actCommand,
  Object.values(SupportedPlaywrightAction),
  {},  // <- Should be `variables`
);

This contrasts with the first call (line 158-161) which correctly passes variables.

Impact

When a user calls:

await stagehand.act("type %password% into the password field", {
  variables: { password: "secret123" }
});

First attempt:

  • Prompt includes: "variables available: %password%"
  • LLM returns: { method: "fill", arguments: ["%password%"] }
  • Action fails (e.g., element not found)

Self-heal attempt (before fix):

  • Prompt does NOT include variables info (empty {})
  • LLM doesn't know %password% is valid
  • LLM returns wrong/empty arguments
  • Action fails or types wrong value

Self-heal attempt (after fix):

  • Prompt includes: "variables available: %password%"
  • LLM returns: { method: "fill", arguments: ["%password%"] }
  • Action succeeds with correct value

Solution

Changed line 368 from {} to variables:

// AFTER (fix):
const instruction = buildActPrompt(
  actCommand,
  Object.values(SupportedPlaywrightAction),
  variables,  // Fix: pass variables instead of {}
);

Test Plan

  • Added regression test self-heal-variables.test.ts (9 test cases)
  • Tests verify buildActPrompt behavior with variables vs empty object
  • Tests simulate the self-heal scenario where variables matter
  • All 9 tests pass

Files Changed

  • packages/core/lib/v3/handlers/actHandler.ts - Pass variables instead of {} in self-heal path
  • packages/core/tests/self-heal-variables.test.ts - New regression test (9 test cases)

Feedback? Email p0@kernel.dev


Summary by cubic

Fixes self-heal retries to pass the variables object to buildActPrompt so prompts include available placeholders and retries use the correct values. Addresses BUG-024.

  • Bug Fixes
    • Pass variables instead of {} in the self-heal path of ActHandler.
    • Added regression test suite to verify prompt content and guard against regressions.

Written for commit 8fa297c. Summary will update on new commits.

When an action fails and self-heal is triggered, the retry call to
buildActPrompt was passing an empty object {} instead of the variables
parameter that's available in scope. This meant the LLM didn't know
about available variable placeholders during self-heal attempts.

The fix changes line 368 from {} to variables, ensuring consistent
behavior between the initial attempt and self-heal retries.

Fixes BUG-024: Self-Heal Loop Uses Empty Variables Object
@changeset-bot
Copy link

changeset-bot bot commented Jan 14, 2026

⚠️ No Changeset found

Latest commit: 8fa297c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 14, 2026

Greptile Summary

Fixed a bug where the self-heal retry mechanism was passing an empty object {} instead of the variables parameter to buildActPrompt. This caused the LLM to lose context about available variable placeholders (like %password%) during self-heal attempts, resulting in incorrect or failed actions.

  • Changed line 368 in actHandler.ts from {} to variables in the self-heal path
  • Added comprehensive regression test suite with 9 test cases
  • The fix ensures variable information is consistently passed to the LLM in both initial and self-heal attempts

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The fix is a straightforward one-line change that corrects an obvious bug by passing the correct parameter. The comprehensive test suite with 9 test cases validates both runtime behavior and source code, ensuring the fix works correctly and preventing regression.
  • No files require special attention

Important Files Changed

Filename Overview
packages/core/lib/v3/handlers/actHandler.ts One-line fix correctly passes variables parameter instead of empty object {} to buildActPrompt in self-heal path (line 368)
packages/core/tests/self-heal-variables.test.ts Comprehensive test suite with 9 tests covering runtime behavior, source code inspection, and buildActPrompt behavior with variables

Sequence Diagram

sequenceDiagram
    participant User
    participant ActHandler
    participant buildActPrompt
    participant LLM
    participant performUnderstudyMethod

    User->>ActHandler: act("type %password%", {variables: {password: "secret"}})
    
    Note over ActHandler: Initial attempt
    ActHandler->>buildActPrompt: buildActPrompt(instruction, actions, variables)
    buildActPrompt-->>ActHandler: "variables available: %password%"
    ActHandler->>LLM: getActionFromLLM(instruction with variables)
    LLM-->>ActHandler: {method: "fill", arguments: ["%password%"]}
    ActHandler->>performUnderstudyMethod: perform action
    performUnderstudyMethod-->>ActHandler: Error: Element not found
    
    Note over ActHandler: Self-heal (BEFORE fix)
    ActHandler->>buildActPrompt: buildActPrompt(actCommand, actions, {})
    buildActPrompt-->>ActHandler: NO variable info ❌
    LLM-->>ActHandler: Wrong/incomplete arguments
    
    Note over ActHandler: Self-heal (AFTER fix)
    ActHandler->>buildActPrompt: buildActPrompt(actCommand, actions, variables)
    buildActPrompt-->>ActHandler: "variables available: %password%"
    ActHandler->>LLM: getActionFromLLM(instruction with variables)
    LLM-->>ActHandler: {method: "fill", arguments: ["%password%"]}
    ActHandler->>performUnderstudyMethod: perform action with new selector
    performUnderstudyMethod-->>ActHandler: Success ✓
    ActHandler-->>User: {success: true}
Loading

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant