Skip to content

add variables to agent#1580

Open
tkattkat wants to merge 2 commits intomainfrom
add-variables-to-agent
Open

add variables to agent#1580
tkattkat wants to merge 2 commits intomainfrom
add-variables-to-agent

Conversation

@tkattkat
Copy link
Collaborator

@tkattkat tkattkat commented Jan 20, 2026

Why

Users need a way to pass sensitive data (passwords, API keys, personal info) to agent executions without exposing the actual values to the LLM. This also enables reusable agent scripts where variable values can change without invalidating cached executions.

Usage

const agent = stagehand.agent({
  model: "google/gemini-3-flash-preview",
  mode: "hybrid"
});

await agent.execute({
  instruction: "Log in to the dashboard",
  variables: {
    username: { value: "john@example.com", description: "The user's email address" },
    password: { value: process.env.USER_PASSWORD, description: "The user's password" },
  },
});

What Changed

  • Added variables option to agent.execute() accepting Record<string, { value: string | number | boolean; description: string }>
  • LLM sees variable names and descriptions in system prompt, uses %variableName% syntax in tool calls
  • Variable substitution implemented in act, type, fillForm, and fillFormVision tools
  • Sensitive values never returned to LLM in tool outputs
  • Cache keys use variable names only (not values) - changing values won't invalidate cache
  • Feature requires experimental: true, not supported in CUA mode
  • Shared utilities in agent/utils/variables.ts

Test Plan

  • Test agent execution with variables for login flow (username/password)
  • Verify LLM correctly uses %variableName% syntax in tool calls
  • Confirm sensitive values don't appear in LLM responses/tool outputs
  • Test cache hit when variable values change but names stay same
  • Verify error thrown when variables used without experimental: true
  • Verify error thrown when variables used with CUA mode

Summary by cubic

Add first-class variables to agent.execute so agents can use named sensitive values without exposing them to the LLM. Cache now keys on variable names, so changing values doesn't invalidate cached runs.

  • New Features
    • Added variables to agent.execute: Record<string, { value: string|number|boolean; description: string }>.
    • System prompt lists variable names/descriptions; LLM uses %variableName% in act, type, fillForm, and fillFormVision.
    • Tools substitute variables at runtime; sensitive values are never returned to the LLM.
    • Cache keys include variable names only; replay substitutes values during execution.
    • Requires experimental: true; not supported in CUA mode (validated with clear errors).
    • New utils: substituteVariables and toActVariables.

Written for commit 3afda5c. Summary will update on new commits.

@changeset-bot
Copy link

changeset-bot bot commented Jan 20, 2026

🦋 Changeset detected

Latest commit: 3afda5c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@browserbasehq/stagehand Patch
@browserbasehq/stagehand-evals Patch
@browserbasehq/stagehand-server Patch

Not sure what this means? Click here to learn what changesets are.

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

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 20, 2026

Greptile Summary

This PR adds a variables feature to agent execution, allowing users to pass sensitive data (passwords, API keys, personal info) without exposing actual values to the LLM. Variables are defined with a value and description, and the LLM uses %variableName% syntax in tool calls which gets substituted with actual values before execution.

Key Implementation Details:

  • Type-safe API: Added Variable, VariableValue, and Variables types with comprehensive JSDoc examples
  • Tool Integration: Variable substitution implemented in act, type, fillForm, and fillFormVision tools using substituteVariables() utility
  • LLM Privacy: Sensitive values never returned to LLM - tool outputs use original %variableName% tokens instead of actual values (see type.ts:96 and fillFormVision.ts:140)
  • Cache Optimization: Cache keys use variable names only (not values) via variableKeys array, enabling cache hits when values change
  • Validation: Properly blocks usage in CUA mode and requires experimental: true flag
  • System Prompt: Variables section dynamically added with descriptions and usage guidance

Implementation Quality:

The implementation is clean and well-architected. Variable substitution uses simple string split().join() approach which handles multiple occurrences correctly. The separation between variable descriptions (visible to LLM) and values (hidden from LLM) is consistently maintained throughout the tool chain.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The implementation is well-designed with proper validation, clean separation of concerns, and maintains backward compatibility. Variable substitution logic is simple and correct, cache integration preserves performance characteristics, and the feature is properly gated behind experimental flag.
  • No files require special attention

Important Files Changed

Filename Overview
packages/core/lib/v3/types/public/agent.ts Added Variable, VariableValue, and Variables types for agent execution, properly documented with JSDoc and examples
packages/core/lib/v3/agent/utils/variables.ts Utility functions for variable substitution (substituteVariables) and conversion (toActVariables) - clean implementation using string split/join
packages/core/lib/v3/agent/tools/type.ts Added variable substitution using substituteVariables() before typing, returns original text with tokens to LLM to hide sensitive values
packages/core/lib/v3/agent/tools/fillFormVision.ts Applies substituteVariables() to each field value before typing, maintains token format in responses
packages/core/lib/v3/agent/utils/validateExperimentalFeatures.ts Added validation to block variables usage in CUA mode and require experimental flag for non-CUA usage
packages/core/lib/v3/cache/AgentCache.ts Cache keys include variable names (not values) via variableKeys array to enable cache hits when values change

Sequence Diagram

sequenceDiagram
    participant User
    participant Agent
    participant SystemPrompt
    participant LLM
    participant Tools
    participant VariableSubstitution

    User->>Agent: execute({variables: {password: {value: "secret123", description: "login password"}}})
    Agent->>SystemPrompt: Build prompt with variable descriptions
    SystemPrompt-->>LLM: Variables: password (login password)<br/>Use %password% syntax
    
    LLM->>Tools: type("%password%", coordinates)
    Tools->>VariableSubstitution: substituteVariables("%password%", variables)
    VariableSubstitution-->>Tools: "secret123"
    Tools->>Browser: page.type("secret123")
    Browser-->>Tools: Success
    
    Note over Tools,LLM: Return original token to LLM
    Tools-->>LLM: {success: true, text: "%password%"}
    
    Note over Agent: Cache key uses variable name only
    Agent->>Cache: Store with variableKeys: ["password"]
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.

2 issues found across 15 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/core/lib/v3/agent/tools/type.ts">

<violation number="1" location="packages/core/lib/v3/agent/tools/type.ts:58">
P1: Logging `actualText` exposes sensitive values (passwords, API keys) in logs. Since the feature's purpose is to protect sensitive data from exposure, consider logging the original `text` with `%variableName%` tokens instead of the substituted values.</violation>
</file>

<file name="packages/core/lib/v3/agent/prompts/agentSystemPrompt.ts">

<violation number="1" location="packages/core/lib/v3/agent/prompts/agentSystemPrompt.ts:221">
P2: Variable descriptions are interpolated into the XML prompt without escaping/CDATA, so descriptions containing XML characters can break the prompt or allow injection. Escape or wrap descriptions before insertion.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Member

@pirate pirate left a comment

Choose a reason for hiding this comment

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

We should extend act to support this better variables format, and then use the same format for both.

The type could be {value: string | {description: string, value: string}}

I really dont want to introduce different shapes on different endpoints. Every bit of drift between the shapes that Agent accepts and the shapes the other endpoints accept is a source of confusion for users.

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.

2 participants