Skip to content

Conversation

@liuxiaopai-ai
Copy link

Summary

Fixes #364

Currently, first and last are only recognized as standalone locator types in the find command (e.g., find first <selector>). This means chaining them as modifiers after semantic locators like role, text, label, etc. fails with an error.

For example, this command fails:

agent-browser find role spinbutton first fill '20'

Because first at position 3 is interpreted as the subaction (like click/fill), not as a modifier.

Changes

CLI Parser (cli/src/commands.rs)

  • After parsing a semantic locator (role, text, label, placeholder, alt, title, testid) and its value, the parser now checks if the next token is first, last, or nth
  • If found, it adds an index field to the JSON command (0 for first, -1 for last, or the specified index for nth) and shifts the remaining arguments accordingly
  • Standalone find first <selector> and find last <selector> continue to work as before (backward compatible)

Server-side Handlers (src/actions.ts, src/types.ts)

  • Added optional index field to GetByRoleCommand, GetByTextCommand, GetByLabelCommand, GetByPlaceholderCommand, GetByAltTextCommand, GetByTitleCommand, and GetByTestIdCommand interfaces
  • Updated all handleGetBy* functions to apply .first(), .last(), or .nth() on the locator when an index field is present

Help Text (cli/src/output.rs)

  • Updated the find command help to document the new modifier syntax with examples

Tests

  • Added 13 new tests covering:
    • find role <role> first/last/nth <n> <action> [value]
    • find text <text> first <action>
    • find label <label> last <action> <value>
    • find placeholder <text> first <action> <value>
    • find testid <id> last <action>
    • Backward compatibility: standalone find first/last <selector> still works
    • Backward compatibility: find role <role> <action> without modifier has no index field

Examples

# Before (fails): first is treated as subaction
agent-browser find role spinbutton first fill '20'

# After (works): first is a modifier, fill is the subaction
agent-browser find role spinbutton first fill '20'
# → getbyrole with role=spinbutton, index=0, subaction=fill, value=20

# Other examples:
agent-browser find text "Submit" last click
agent-browser find label "Email" nth 2 fill "user@example.com"
agent-browser find role listitem nth 3 click

@vercel
Copy link
Contributor

vercel bot commented Feb 7, 2026

@liuxiaopai-ai is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2322f309c6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +891 to +893
if (command.index !== undefined) {
locator = command.index === -1 ? locator.last() : locator.nth(command.index);
}

Choose a reason for hiding this comment

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

P1 Badge Propagate semantic locator index through validation

These handlers now rely on command.index to apply .last()/.nth(), but the command validator in src/protocol.ts still does not define an index field for any getby* schema and dispatches result.data from safeParse. That means the new index emitted by the CLI is dropped before execution, so commands like find role spinbutton first click still target the unscoped locator and can fail when multiple matches exist.

Useful? React with 👍 / 👎.

Comment on lines +925 to +927
case 'fill':
await locator.fill(command.value ?? '');
return successResponse(command.id, { filled: true });

Choose a reason for hiding this comment

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

P2 Badge Accept getbytext fill in protocol schema

A fill path was added here for getbytext, but src/protocol.ts still validates getbytext.subaction as only click or hover. As a result, find text ... fill ... is rejected during command parsing and never reaches this branch, so the new behavior is effectively broken despite the type/handler changes.

Useful? React with 👍 / 👎.

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.

find: first/last cannot be used as modifiers after role/text locators

1 participant