Skip to content
Open
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
3008f7f
fix: invalid test case
Hungerarray Feb 21, 2025
76202e8
add: string response to json unmarshal failures
Hungerarray Feb 21, 2025
b41b82d
bump: locator lib to 0.43.0
Hungerarray Feb 21, 2025
1a9fd2f
add: logs about request url
Hungerarray Feb 21, 2025
ccb4f12
bump: version to v0.44.0
Hungerarray Feb 21, 2025
13331b7
fix: visible elements are hidden in iOS.
Hungerarray Mar 3, 2025
d71414a
fix: struct packing logic
Hungerarray Mar 23, 2025
9ae785f
add: additional logs for context
Hungerarray Mar 24, 2025
2700f1d
add: tracing helpers
Hungerarray Mar 24, 2025
12d3ce4
add: tracing configs
Hungerarray Mar 24, 2025
4a3ce88
add: OTEL SDK Setup
Hungerarray Mar 24, 2025
3c60f1d
update: sync between connnections
Hungerarray Mar 24, 2025
22e1075
add: manual tracing points
Hungerarray Mar 24, 2025
68e19e1
add: tracing options
Hungerarray Mar 24, 2025
983a702
add: trace logs
Hungerarray Mar 24, 2025
e45687f
add: support for trace parent id
Hungerarray Mar 24, 2025
c7e3b06
add: otel parent trace id
Hungerarray Mar 24, 2025
da2b39f
add: raw xml worker
Hungerarray Mar 25, 2025
b39340b
add: noop span trace
Hungerarray Mar 25, 2025
bffd601
update: unify tracing
Hungerarray Mar 25, 2025
1a0b8d7
fix: IsValidLocator on rawxml
Hungerarray Mar 25, 2025
fbc4186
update: locatr prompt
Hungerarray Mar 25, 2025
ba8c8a5
update: valid locator check
Hungerarray Mar 25, 2025
f06d788
update: improve xpath generation logic
Hungerarray Mar 26, 2025
2fed58d
fix: xml xpath generation
Hungerarray Mar 26, 2025
ddd3944
remove: TopP from LLM call
Hungerarray Mar 26, 2025
d056473
update: generate locator for all element
Hungerarray Mar 26, 2025
f4652d8
fix: element Unique ID
Hungerarray Mar 26, 2025
67c880f
update: xpath index
Hungerarray Mar 26, 2025
ed4d07b
fix: indexing
Hungerarray Mar 26, 2025
3c34fd4
fix: indexing
Hungerarray Mar 27, 2025
9edb99e
update: index
Hungerarray Mar 27, 2025
be1228a
update: bump project version
Hungerarray Mar 28, 2025
267baa5
add: appium cache client
Hungerarray Apr 2, 2025
b5168bf
update: use appium cache client
Hungerarray Apr 2, 2025
c89835a
bump: version
Hungerarray Apr 2, 2025
93bd7c7
Fix selenium panic on empty tracer (#50)
Hungerarray Nov 11, 2025
95ae0bc
fix: nil dereference with err is nil
Hungerarray Nov 11, 2025
e58a453
update: locatr version
Hungerarray Nov 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion eval/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"flag"
"fmt"
"time"
Expand Down Expand Up @@ -79,7 +80,9 @@ func runEval(browser playwright.Browser, eval *evalConfigYaml) []evalResult {
continue
}

locatrOutput, err := playWrightLocatr.GetLocatr(step.UserRequest)
ctx := context.Background()

locatrOutput, err := playWrightLocatr.GetLocatr(ctx, step.UserRequest)
if err != nil {
logger.Logger.Error("Error getting locator for step", "stepName", step.Name, "error", err)
results = append(results, evalResult{
Expand Down
5 changes: 4 additions & 1 deletion eval/utils.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"encoding/csv"
"fmt"
"os"
Expand Down Expand Up @@ -31,6 +32,7 @@ func getAllYamlFiles(folder string) ([]string, error) {
"folder", folder, "fileCount", len(res))
return res, nil
}

func contains(locatrs []string, loc string) bool {
for _, l := range locatrs {
if l == loc {
Expand All @@ -48,6 +50,7 @@ func compareSlices(yamlLocatrs []string, locatrs []string) bool {
}
return false
}

func readYamlFile(filePath string) (*evalConfigYaml, error) {
yamlFile, err := os.ReadFile(filePath)
if err != nil {
Expand Down Expand Up @@ -81,7 +84,7 @@ func getLocatrFromYamlConfig(evalConfig *evalConfigYaml, page playwright.Page) *
reRankClient := reranker.NewCohereClient(os.Getenv("COHERE_API_KEY"))
locatrOptions.ReRankClient = reRankClient
}
return playwrightLocatr.NewPlaywrightLocatr(page, locatrOptions)
return playwrightLocatr.NewPlaywrightLocatr(context.Background(), page, locatrOptions)
}

func writeEvalResultToCsv(results []evalResult, fileName string) {
Expand Down
48 changes: 45 additions & 3 deletions examples/appium/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package main

import (
"context"
"errors"
"fmt"
"log/slog"
"os"
Expand All @@ -9,11 +11,50 @@ import (
appiumLocatr "github.com/vertexcover-io/locatr/golang/appium"
"github.com/vertexcover-io/locatr/golang/llm"
"github.com/vertexcover-io/locatr/golang/logger"
"github.com/vertexcover-io/locatr/golang/tracing"
)

type Config struct {
Tracing struct {
Endpoint string
ServiceName string
Insecure bool
}
}

func main() {
ctx := context.Background()

logger.Level.Set(slog.LevelDebug)

cfg := Config{}
cfg.Tracing.Endpoint = "localhost:4317"
cfg.Tracing.ServiceName = "locator"
cfg.Tracing.Insecure = true

shutdown, err := tracing.SetupOtelSDK(
context.Background(),
tracing.WithEndpoint(cfg.Tracing.Endpoint),
tracing.WithSVCName(cfg.Tracing.ServiceName),
tracing.WithInsecure(cfg.Tracing.Insecure),
)
if err != nil {
logger.Logger.Error(
"Failed to setup Open Telemetry SDK",
slog.String("error", err.Error()),
)
os.Exit(1)
}
defer func() {
if sErr := shutdown(context.Background()); sErr != nil {
err = errors.Join(err, sErr)
logger.Logger.Error(
"Error while shutting down Open Telemetry service",
slog.String("error", err.Error()),
)
}
}()

llmClient, _ := llm.NewLlmClient(
llm.OpenAI, // (openai | anthropic),
os.Getenv("OPENAI_MODEL"),
Expand All @@ -23,15 +64,16 @@ func main() {
LlmClient: llmClient,
}
aLocatr, err := appiumLocatr.NewAppiumLocatr(
ctx,
"http://localhost:4723",
"640daa1b-afdc-45a3-83fd-d0c37cffb3de", bLocatr,
"b97d1a76-3ad5-44a5-840d-286294d94bfc", bLocatr,
)
if err != nil {
fmt.Println("failed creating appium locatr locatr", err)
return
}
desc := "This input element is designed for password entry, indicated by its type attribute set to \"password,\" which obscures the text entered for privacy. It requires user input, as denoted by the \"required\" attribute, ensuring that users do not submit the form without filling out this field. The placeholder text prompts users to \"Enter your password,\" guiding them on the expected input. This input is commonly used within forms where sensitive data is collected, such as registration or login forms."
l, err := aLocatr.GetLocatrStr(desc)
desc := "This EditText element for 'Email' serves as the second interactive entry point for user input in a linear sequence, positioned directly below an ImageView-containing LinearLayout which implies a visual hierarchy. It follows a specific order that leads to it being the first editable text input provided in the context, indicating its primary role in user authentication workflows."
l, err := aLocatr.GetLocatrStr(ctx, desc)
if err != nil {
fmt.Println("error getting locatr", err)
}
Expand Down
7 changes: 5 additions & 2 deletions examples/cdp/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"fmt"
"log"
"os"
Expand All @@ -11,6 +12,8 @@ import (
)

func main() {
ctx := context.Background()

reRankClient := reranker.NewCohereClient(os.Getenv("COHERE_API_KEY"))

options := locatr.BaseLocatrOptions{
Expand All @@ -22,7 +25,7 @@ func main() {
connectionOpts := cdpLocatr.CdpConnectionOptions{
Port: 9222,
}
connection, err := cdpLocatr.CreateCdpConnection(connectionOpts)
connection, err := cdpLocatr.CreateCdpConnection(ctx, connectionOpts)
if err != nil {
fmt.Println(err)
return
Expand All @@ -36,7 +39,7 @@ func main() {
return
}

newsItem, err := cdpLocatr.GetLocatrStr("First news link")
newsItem, err := cdpLocatr.GetLocatrStr(ctx, "First news link")
if err != nil {
log.Fatalf("could not get locator: %v", err)
return
Expand Down
7 changes: 5 additions & 2 deletions examples/default-llm-client/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Example on how to use locatr without passing the llm client.
*/

import (
"context"
"log"
"time"

Expand All @@ -15,6 +16,8 @@ import (
)

func main() {
ctx := context.Background()

pw, err := playwright.Run()
if err != nil {
log.Fatalf("could not start playwright: %v", err)
Expand Down Expand Up @@ -44,9 +47,9 @@ func main() {
UseCache: true,
} // llm client is created by default by reading the environment variables.

playWrightLocatr := playwrightLocatr.NewPlaywrightLocatr(page, options)
playWrightLocatr := playwrightLocatr.NewPlaywrightLocatr(ctx, page, options)

_, err = playWrightLocatr.GetLocatr("Search Docker Hub input field")
_, err = playWrightLocatr.GetLocatr(ctx, "Search Docker Hub input field")
if err != nil {
log.Fatalf("could not get locator: %v", err)
}
Expand Down
14 changes: 10 additions & 4 deletions examples/dockerhub/docker_hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Example on how to use locatr with playwright to interact with docker hub.
*/

import (
"context"
"log"
"os"
"time"
Expand All @@ -17,6 +18,8 @@ import (
)

func main() {
ctx := context.Background()

pw, err := playwright.Run()
if err != nil {
log.Fatalf("could not start playwright: %v", err)
Expand Down Expand Up @@ -53,9 +56,9 @@ func main() {
ResultsFilePath: "docker_hub.json",
}

playWrightLocatr := playwrightLocatr.NewPlaywrightLocatr(page, options)
playWrightLocatr := playwrightLocatr.NewPlaywrightLocatr(ctx, page, options)

sBarLoc, err := playWrightLocatr.GetLocatr("Search Docker Hub input field")
sBarLoc, err := playWrightLocatr.GetLocatr(ctx, "Search Docker Hub input field")
if err != nil {
log.Fatalf("could not get locator: %v", err)
}
Expand All @@ -70,7 +73,10 @@ func main() {
}
time.Sleep(5 * time.Second)

pLink, err := playWrightLocatr.GetLocatr("Link to python repo on docker hub. It has the following description: 'Python is an interpreted, interactive, object-oriented, open-source programming language.'")
pLink, err := playWrightLocatr.GetLocatr(
ctx,
"Link to python repo on docker hub. It has the following description: 'Python is an interpreted, interactive, object-oriented, open-source programming language.'",
)
if err != nil {
log.Fatalf("could not get locator: %v", err)
}
Expand All @@ -81,7 +87,7 @@ func main() {
}
time.Sleep(3 * time.Second)

tagsLoc, err := playWrightLocatr.GetLocatr("Tags tab on the page. It is made up of anchor tag")
tagsLoc, err := playWrightLocatr.GetLocatr(ctx, "Tags tab on the page. It is made up of anchor tag")
playWrightLocatr.WriteResultsToFile()
if err != nil {
log.Fatalf("could not get locator: %v", err)
Expand Down
8 changes: 5 additions & 3 deletions examples/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package main
Example on how to use locatr with playwright to interact with github.
*/
import (
"context"
"fmt"
"log"
"os"
Expand Down Expand Up @@ -51,10 +52,11 @@ func main() {
log.Fatalf("could not create llm client: %v", err)
}
options := locatr.BaseLocatrOptions{UseCache: true, LlmClient: llmClient}
ctx := context.Background()

locatr := playwrightLocatr.NewPlaywrightLocatr(page, options)
locatr := playwrightLocatr.NewPlaywrightLocatr(ctx, page, options)

cDropDownLoc, err := locatr.GetLocatr("<> Code dropdown")
cDropDownLoc, err := locatr.GetLocatr(ctx, "<> Code dropdown")
if err != nil {
log.Fatalf("could not get locator: %v", err)
return
Expand All @@ -64,7 +66,7 @@ func main() {
return
}

dZipLoc, err := locatr.GetLocatr("Download ZIP button on the opened dropdown")
dZipLoc, err := locatr.GetLocatr(ctx, "Download ZIP button on the opened dropdown")
if err != nil {
log.Fatalf("could not get download ZIP locator: %v", err)
return
Expand Down
6 changes: 4 additions & 2 deletions examples/rerank/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Example on how to use locatr without passing the llm client.
*/

import (
"context"
"log"
"os"
"time"
Expand Down Expand Up @@ -48,9 +49,10 @@ func main() {
ReRankClient: reRankClient,
} // llm client is created by default by reading the environment variables.

playWrightLocatr := playwrightLocatr.NewPlaywrightLocatr(page, options)
ctx := context.Background()
playWrightLocatr := playwrightLocatr.NewPlaywrightLocatr(ctx, page, options)

nItem, err := playWrightLocatr.GetLocatr("First news link")
nItem, err := playWrightLocatr.GetLocatr(ctx, "First news link")
if err != nil {
log.Fatalf("could not get locator: %v", err)
}
Expand Down
16 changes: 12 additions & 4 deletions examples/selenium/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"fmt"
"log"
"os"
Expand All @@ -22,13 +23,15 @@ func main() {
caps := selenium.Capabilities{}
caps.AddChrome(chrome.Capabilities{Args: []string{}})

defer service.Stop()
defer func() {
_ = service.Stop()
}()
driver, err := selenium.NewRemote(caps, "")
if err != nil {
log.Fatal(err)
return
}
driver.Get("https://news.ycombinator.com/")
_ = driver.Get("https://news.ycombinator.com/")

reRankClient := reranker.NewCohereClient(os.Getenv("COHERE_API_KEY"))

Expand All @@ -40,8 +43,13 @@ func main() {
// wait for page to load
time.Sleep(3 * time.Second)

ctx := context.Background()
seleniumLocatr, err := seleniumLocatr.NewRemoteConnSeleniumLocatr(
"http://localhost:4444/wd/hub", "ca0d56a6a3dcfc51eb0110750f0abab7", options) // the path must end with /wd/hub
ctx,
"http://localhost:4444/wd/hub",
"ca0d56a6a3dcfc51eb0110750f0abab7",
options,
) // the path must end with /wd/hub

/*
or: directly pass the driver
Expand All @@ -51,7 +59,7 @@ func main() {
log.Fatal(err)
return
}
newsLocatr, err := seleniumLocatr.GetLocatrStr("First news link in the site..")
newsLocatr, err := seleniumLocatr.GetLocatrStr(ctx, "First news link in the site..")
if err != nil {
log.Fatal(err)
return
Expand Down
10 changes: 6 additions & 4 deletions examples/steam/steam.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Example on how to use locatr with playwright to interact with steam.
*/

import (
"context"
"fmt"
"log"
"os"
Expand Down Expand Up @@ -56,10 +57,11 @@ func main() {
log.Fatalf("could not create llm client: %v", err)
}
options := locatr.BaseLocatrOptions{UseCache: true, LlmClient: llmClient}
ctx := context.Background()

playWrightLocatr := playwrightLocatr.NewPlaywrightLocatr(page, options)
playWrightLocatr := playwrightLocatr.NewPlaywrightLocatr(ctx, page, options)

sBarLoc, err := playWrightLocatr.GetLocatr("Search input bar on the steam store.")
sBarLoc, err := playWrightLocatr.GetLocatr(ctx, "Search input bar on the steam store.")
if err != nil {
log.Fatalf("could not get search bar locator: %v", err)
}
Expand All @@ -73,7 +75,7 @@ func main() {
}
time.Sleep(5 * time.Second)

cStrikeLoc, err := playWrightLocatr.GetLocatr("Counter Strike 2 game on the list")
cStrikeLoc, err := playWrightLocatr.GetLocatr(ctx, "Counter Strike 2 game on the list")
if err != nil {
log.Fatalf("could not get Counter Strike 2 locator: %v", err)
return
Expand All @@ -84,7 +86,7 @@ func main() {
}
time.Sleep(5 * time.Second)

sysReqLoc, err := playWrightLocatr.GetLocatr("System Requirements section on the game page.")
sysReqLoc, err := playWrightLocatr.GetLocatr(ctx, "System Requirements section on the game page.")
if err != nil {
log.Fatalf("could not get system requirements locator: %v", err)
return
Expand Down
Loading