# Technical Documentation: microsoft/fara

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/microsoft/fara)

### Overview (`README.md`)

<div align="center">

# Fara1.5 – A family of frontier computer use agent models



<img src="figures/fara_hero_barchart.png" alt="Fara1.5 Performance" width="600"/>

[](https://aka.ms/fara1.5)
[](https://arxiv.org/abs/2606.20785)
[](https://aka.ms/fara1.5-4B-foundry)
[](https://aka.ms/fara1.5-9B-foundry)
[](https://aka.ms/fara1.5-27B-foundry)

[](https://aka.ms/fara1.5-hf)
[](https://huggingface.co/datasets/microsoft/WebTailBench)
[](https://huggingface.co/datasets/microsoft/CUAVerifierBench)

</div>

---

## Updates

* **2026-07-22** — **Fara1.5 released!** A family of native computer use
  agents at three scales (Fara1.5-4B, Fara1.5-9B, Fara1.5-27B) built on
  Qwen3.5 and trained on data from the **FaraGen1.5** pipeline. **All three models have weights available on [Hugging Face](https://aka.ms/fara1.5-hf) and can be hosted through Microsoft Foundry ([Fara1.5-4B](https://aka.ms/fara1.5-4B-foundry), [Fara1.5-9B](https://aka.ms/fara1.5-9B-foundry), [Fara1.5-27B](https://aka.ms/fara1.5-27B-foundry))**.
  Fara1.5-9B
  reaches 63.4% on Online-Mind2Web and 86.6% on WebVoyager, a new state of
  the art for its size class; Fara1.5-27B achieves 72.3% on Online-Mind2Web,
  outperforming much larger proprietary systems. Read the
  [paper](https://arxiv.org/abs/2606.20785) and the
  [blog post](https://www.microsoft.com/en-us/research/articles/fara1-5-computer-use-agent/).
* **2026-05-12** — **WebTailBench** is now a first-class benchmark in this
  repo: the loader auto-downloads tasks and rubrics from
  [`microsoft/WebTailBench`](https://huggingface.co/datasets/microsoft/WebTailBench)
  (use the refreshed `test_v2` split; a V1↔V2 diff is hosted
  [here](https://microsoft.github.io/fara/docs/webtailbench_v1_v2_diff.html)),
  the **Universal Verifier** (`MMRubricAgent`) is the official judge, and the
  reproducibility CLI lives in `webeval/scripts/webtailbench.py` (stand-alone
  re-scoring via `webeval/scripts/verify_trajectories.py`).
* **2026-04-19** — Released **[CUAVerifierBench](https://huggingface.co/datasets/microsoft/CUAVerifierBench)**,
  a human-annotated benchmark for evaluating CUA verifiers (i.e. judges that
  score agent trajectories). Two splits — `fara7b_om2w_browserbase` (106
  Fara-7B Online-Mind2Web/Browserbase trajectories, ~2 reviewers each) and
  `internal` (154 trajectories from a heldout aurora-v2 task suite) —
  with per-judge UV-blind / UV-informed labels, Universal Verifier
  outputs, and legacy verifier outputs side-by-side. The build script
  that produced the dataset lives alongside the data on Hugging Face.

---

## Overview

**Fara1.5** is a family of native Computer Use Agents (CUAs) at three scales — **Fara1.5-4B**, **Fara1.5-9B**, and **Fara1.5-27B** — built on Qwen3.5 and trained with supervised finetuning on data from **FaraGen1.5**, our scalable data pipeline of environments, solvers, and verifiers. Each model sets a new state of the art for its size class on browser-use benchmarks, and Fara1.5-27B outperforms much larger proprietary systems such as OpenAI Operator and Gemini 2.5 Computer Use on Online-Mind2Web.

Fara1.5 models operate through an observe-think-act loop: given a screenshot of the browser and the conversation history, the model reasons about the state of the task and outputs an action — mouse and keyboard inputs on directly predicted coordinates, web searches, or context management operations — with no accessibility trees or separate parsing models.

<div align="center">
<img src="figures/fig2_fara_agentic_loop.png" alt="Fara1.5 Observe-Think-Act Loop" width="800"/>
</div>

All three models are available on Microsoft Foundry: [Fara1.5-4B](https://ai.azure.com/catalog/models/Fara1.5-4B), [Fara1.5-9B](https://ai.azure.com/catalog/models/Fara1.5-9B), and [Fara1.5-27B](https://ai.azure.com/catalog/models/Fara1.5-27B).

Try Fara1.5-9B as follows (see [Installation](#installation) for detailed instructions):

```bash
# 1. Clone repository
git clone https://github.com/microsoft/fara.git
cd fara

# 2. Setup environment
python3 -m venv .venv 
source .venv/bin/activate
pip install -e .
playwright install
```

Deploy Fara1.5-9B from the [Microsoft Foundry catalog](https://ai.azure.com/catalog/models/Fara1.5-9B) and put your endpoint in a config JSON (e.g. `azure_foundry_config.json`):

```json
{
    "model": "Fara1.5-9B",
    "base_url": "https://your-endpoint.inference.ml.azure.com/",
    "api_key": "YOUR_API_KEY_HERE"
}
```

Then you can iteratively query it with:
```bash
fara-cli --task "whats the weather in new york now" --endpoint_config azure_foundry_config.json
```

To try Fara inside Magentic-UI — a sandboxed browser environment with auditable action logging and user prompts at critical points — follow the instructions in the [Magentic-UI repo](https://github.com/microsoft/magentic-ui). You will need a model endpoint as before, but instead of fara-cli you can use Magentic-UI which has a nice UI (see video demos below).

Note: If you're using Windows, we highly recommend using WSL2 (Windows Subsystem for Linux). Please see the Windows instructions in the [Installation](#installation) section.

<table>
<tr>
<td width="50%" align="center">

<video src="https://github.com/user-attachments/assets/35e9e981-e20b-4ece-961b-60ef4d3b0644" width="100%" style="max-height: 300px;">
</video>

</td>
<td width="50%" align="center">

<video src="https://github.com/user-attachments/assets/d84be15a-c4cd-45f3-9096-b3ad77b94093" width="100%" style="max-height: 300px;">
</video>

</td>
</tr>
<tr>
<td width="50%" align="center">

<video src="https://github.com/user-attachments/assets/ac817f8a-aeab-450b-9ed1-b146bac817fc" width="100%" style="max-height: 300px;">
</video>

</td>
<td width="50%" align="center">

<video src="https://github.com/user-attachments/assets/fe3627c6-e9e7-44dd-bd20-27cedc2be961" width="100%" style="max-height: 300px;">
</video>

</td>
</tr>
</table>

### What Makes Fara1.5 Unique

Unlike traditional chat models that generate text-based responses, Fara1.5 leverages computer interfaces—mouse and keyboard—to perform multi-step tasks on behalf of users. The models:

- **Operate visually** by perceiving webpages and taking actions like scrolling, typing, and clicking on directly predicted coordinates without accessibility trees or separate parsing models
- **Enable efficient deployment** thanks to their compact sizes (4B/9B/27B), resulting in reduced latency and improved privacy
- **Interact with users**: trained with a user simulator on multi-turn rollouts, Fara1.5 can ask for missing information, flag ambiguous tasks, and pause for approval before irreversible actions
- **Remain a research preview**: safety measures include refusing harmful tasks based on responsible AI policies, prompting users at critical interaction points, and auditable action logging through Magentic-UI's sandboxed browser environment

### FaraGen1.5: Scalable Learning Environments

Collecting computer use data from human demonstrations is expensive and slow. **FaraGen1.5** is a scalable data pipeline composed of three modular components:

- **Environments** — open-internet tasks on live websites plus six synthetic FaraEnvs (Mail, Calendar, Stream, ML, Stay, Scheduler): functional UI clones that faithfully simulate domains gated by authentication or requiring irreversible actions, and unlock execution-based, ground-truth verification
- **Solvers** — a solver harness that can be powered by multiple models, including strong frontier models such as GPT-5.4, paired with a user simulator to enable multi-turn rollouts
- **Verifiers** — three complementary filters covering task correctness (the Universal Verifier LLM-judge), efficiency (scoring redundant actions), and critical-point adherence / user interaction (missing information, ambiguous tasks, unapproved irreversible actions)

The resulting training mix contains roughly 2M samples: ~60% web trajectories, 12.8% synthetic environments, 12.5% form filling, 8.8% grounding, 4.9% VQA, and 0.8% GUI drag tasks.

### Key Capabilities

Fara1.5 can automate everyday web tasks including:
- Searching for information and summarizing results
- Filling out forms and managing accounts
- Booking travel, movie tickets, and restaurant reservations
- Shopping and comparing prices across retailers
- Finding job postings and real estate listings

### Performance Highlights

Each Fara1.5 model sets a new state of the art for its size class. Fara1.5-9B improves over Fara-7B by +29.3 points on Online-Mind2Web, +13.1 points on WebVoyager, and +8.2 points on WebTailBench outcome success:

| Model | Size | WebVoyager | Online-Mind2Web | WebTailBench v1.5 (Process) | WebTailBench v1.5 (Outcome) |
|-------|------|------------|-----------------|-----------------------------|-----------------------------|
| **Larger and proprietary agents** | | | | | |
| o3 SoM | - | 79.3 | 55.4 | 69.5 | 35.0 |
| GPT-5 SoM | - | 90.6 | 57.7 | 69.2 | 45.1 |
| Gemini 2.5 Computer Use† | - | - | 57.3 | - | - |
| OpenAI Operator† | - | 87.0 | 58.3 | - | - |
| Yutori Navigator (n1)† | - | - | 64.7 | - | - |
| GUI-Owl-1.5† | 32B | 82.0 | - | - | - |
| Holo2† | 30B-A3B | 83.0 | - | - | - |
| **Similarly sized agents** | | | | | |
| Fara-7B | 7B | 73.5 | 34.1 | 48.8 | 24.1 |
| MolmoWeb† | 8B | 78.2 | 35.3 | - | - |
| Holo2† | 8B | 80.2 | - | - | - |
| GUI-Owl-1.5† | 8B | 78.1 | 48.6 | - | - |
| **Fara1.5 family (ours)** | | | | | |
| **Fara1.5-4B** | 4B | 80.8 | 57.3 | 60.3 | 27.4 |
| **Fara1.5-9B** | 9B | 86.6 | 63.4 | 64.5 | 32.3 |
| **Fara1.5-27B** | 27B | **89.3** | **72.3** | 72.9 | 40.2 |
| FaraGen1.5 Solver (GPT-5.4) | - | 93.4 | 83.4 | 79.6 | 57.4 |

*Table: Task success rate (%) on WebVoyager, Online-Mind2Web, and WebTailBench v1.5. For WebTailBench v1.5 we report both Process Success (correct intermediate steps) and Outcome Success (final task state correct). All Fara1.5 and Fara-7B numbers are averaged over three independent runs. The GPT-5.4-based FaraGen1.5 solver is an upper-bound reference for the SFT-based distillation. † denotes numbers sourced from the model's official release or leaderboard rather than re-run by us.*

### WebTailBench: Evaluating Real-World Web Tasks

**[WebTailBench](https://huggingface.co/datasets/microsoft/WebTailBench)** is our evaluation benchmark focusing on 11 real-world task types that are underrepresented or missing in existing benchmarks. The benchmark includes 609 tasks across diverse categories, with the first 8 segments testing single skills or objectives (usually on a single website), and the remaining 3 evaluating more difficult multi-step or cross-site tasks (shopping lists, comparison shopping, and compositional tasks). Tasks and precomputed rubrics are on Hugging Face (use the refreshed `test_v2` split), the **Universal Verifier** (`MMRubricAgent`) is the official judge, and the reproducibility CLI lives in `webeval/scripts/webtailbench.py`.

### CUAVerifierBench: Evaluating the Verifiers Themselves

While WebTailBench measures *agents*, **[CUAVerifierBench](https://huggingface.co/datasets/microsoft/CUAVerifierBench)** measures the *judges that score those agents*. Each row pairs a Fara agent trajectory (instruction, screenshots, web_surfer log, final answer) with one human reviewer's verdict, plus the verdicts produced by the **Universal Verifier (`MMRubricAgent`)** and several legacy verifiers — so researchers can compute verifier–human agreement (Cohen's κ, accuracy, F1) on a fixed corpus and iterate on new judge prompts / architectures against a frozen ground-truth set.

The dataset is exposed as two Hugging Face configs joinable on `task_id`:

| Config | Granularity | Contents |
|---|---|---|
| `trajectories` | one row per task | instruction, screenshots, web_surfer log, verifier outputs, task-level human aggregates |
| `annotations` | one row per (task, judge) | per-reviewer outcome / process labels and free-text justifications |

Two splits ship today:

| Split | Source | Trajectories | Annotation rows |
|---|---|---|---|
| `fara7b_om2w_browserbase` | Fara-7B trajectories on Online-Mind2Web tasks executed via Browserbase | 106 | 215 (≈2 reviewers/task; UV-blind **and** UV-informed stages) |
| `internal` | Heldout aurora-v2 task suite scored with the same WebSurfer + verifier stack | 154 | 154 (1 reviewer/task; UV-blind only) |

Reviewer identities are anonymized as `Judge1` … `JudgeN` using a single shared map across both splits. The build script that produced the dataset (with full schema + provenance) ships alongside the data on Hugging Face at [`microsoft/CUAVerifierBench`](https://huggingface.co/datasets/microsoft/CUAVerifierBench); see the [dataset README](https://huggingface.co/datasets/microsoft/CUAVerifierBench/blob/main/README.md) for the full column list.

```python
from datasets import load_dataset

trajs = load_dataset("microsoft/CUAVerifierBench", "trajectories",
                     split="fara7b_om2w_browserbase")
anns  = load_dataset("microsoft/CUAVerifierBench", "annotations",
                     split="fara7b_om2w_browserbase")
```

### Evaluation Infrastructure

Our evaluation setup leverages:

1. **Playwright** - A cross-browser automation framework that replicates browser environments
2. **Abstract Web Agent Interface** - Allows integration of any model from any source into the evaluation environment
3. **Fara-Agent Class** - Reference implementation for running the Fara models

> **Note:** Fara1.5 is a research preview designed to invite hands-on exploration and feedback from the community. We recommend running it in a sandboxed environment, monitoring its execution, and avoiding sensitive data or high-risk domains.

---

## Installation


### Linux 

The following instructions are for Linux systems, see the Windows section below for Windows instructions. 

Install the package using pip and set up the environment with Playwright:

```bash
# 1. Clone repository
git clone https://github.com/microsoft/fara.git
cd fara

# 2. Setup environment
python3 -m venv .venv 
source .venv/bin/activate
pip install -e .[vllm]
playwright install
```

Note: If you plan on hosting with Microsoft Foundry only, you can skip the `[vllm]` and just do `pip install -e .`


### Windows

For Windows, we highly recommend using WSL2 (Windows Subsystem for Linux) to provide a Linux-like environment. However, if you prefer to run natively on Windows, follow these steps:

```bash
# 1. Clone repository
git clone https://github.com/microsoft/fara.git
cd fara

# 2. Setup environment
python3 -m venv .venv
.venv\Scripts\activate
pip install -e .
python3 -m playwright install
```

### Hosting the Model

**Recommended:** The easiest way to get started is using Microsoft Foundry hosting, which requires no GPU hardware or model downloads. All three Fara1.5 models are available on Foundry.

#### Microsoft Foundry Hosting

Deploy Fara1.5 models from the Microsoft Foundry catalog ([Fara1.5-4B](https://aka.ms/fara1.5-4B-foundry), [Fara1.5-9B](https://aka.ms/fara1.5-9B-foundry), [Fara1.5-27B](https://aka.ms/fara1.5-27B-foundry)) without needing to download weights or manage GPU infrastructure.

**Setup:**

1. Deploy the model on Microsoft Foundry and obtain your endpoint URL and API key

Then create a endpoint configuration JSON file (e.g., `azure_foundry_config.json`):

```json
{
    "model": "Fara1.5-9B",
    "base_url": "https://your-endpoint.inference.ml.azure.com/",
    "api_key": "YOUR_API_KEY_HERE"
}
```

2. Run the Fara agent:

```bash
fara-cli --task "how many pages does wikipedia have" --endpoint_config azure_foundry_config.json [--headful]
```

Note: you can also specify the endpoint config with the args `--base_url [your_base_url] --api_key [your_api_key] --model [your_model_name]` instead of using a config JSON file. 

Note: If you see an error that the `fara-cli` command is not found, then try:

```bash
python -m fara.run_fara --task "what is the weather in new york now"
```

That's it! No GPU or model downloads required.

#### Self-hosting with vLLM

If you have access to GPU resources, you can download the model weights from [Hugging Face](https://aka.ms/fara1.5-hf), self-host Fara models with vLLM, and point `fara-cli` at the resulting OpenAI-compatible endpoint:

```bash
vllm serve <model> --port 5000 --dtype auto
```

The previous-generation [Fara-7B](https://huggingface.co/microsoft/Fara-7b) weights remain available on Hugging Face (with [GGUF variants](https://huggingface.co/bartowski/microsoft_Fara-7B-GGUF) for LM Studio / Ollama). Pass `--fara-7b` to run the Fara-7B agent instead of Fara1.5:

```bash
fara-cli --fara-7b --task "how many pages does wikipedia have" --endpoint_config fara7b_config.json
```

If you didn't use vLLM to host, specify `--base_url [your_base_url] --api_key [your_api_key] --model [your_model_name]` when running `fara-cli`. Please ensure that context length is set to at least 15000 tokens and temperature to 0 for best results.

Runs save a full trajectory — per-step screenshots and a `data_point.json` (task, actions, observations, and outcome) — to the folder passed via `--output_folder`.

## Reproducibility

Instructions to reproduce our benchmark results (WebVoyager, Online-Mind2Web, WebTailBench) with the `webeval/` framework — including installation, the per-benchmark CLIs, BrowserBase setup, and result analysis — live in [`docs/eval_reproducibility.md`](docs/eval_reproducibility.md).

> **Note:** the webeval pipeline documented there produced the previous-generation (Fara-7B) numbers and is being updated for the Fara1.5 evaluation stack.

## Citation

If you use Fara1.5 in your research, please use the following BibTeX entry.
```bibtex
@article{fara152026,
  title={Fara1.5: Scalable Learning Environments for Computer Use Agents},
  author={Awadallah, Ahmed and Gupta, Sahil and Lara, Yash and Lu, Yadong and Mozannar, Hussein and Nambi, Akshay and Nussbaum, Zach and Pandya, Yash and Rajeswaran, Aravind and Rosset, Corby and Taymanov, Alexey and do Valle, Luiz and Vineet, Vibhav and Whitehead, Spencer and Zhao, Andrew},
  journal={arXiv:2606.20785},
  year={2026}
}
```

For the previous generation, Fara-7B:
```bibtex
@article{fara7b2025,
  title={Fara-7B: An Efficient Agentic Model for Computer Use},
  author={Awadallah, Ahmed and Lara, Yash and Magazine, Raghav and Mozannar, Hussein and Nambi, Akshay and Pandya, Yash and Rajeswaran, Aravind and Rosset, Corby and Taymanov, Alexey and Vineet, Vibhav and Whitehead, Spencer and Zhao, Andrew},
  journal={arXiv:2511.19663},
  year={2025}
}
```

---

### Overview (`webeval/README.md`)

# webeval

Evaluation framework for [Fara-7B](https://huggingface.co/microsoft/Fara-7B)
on agentic web benchmarks (WebVoyager, OnlineMind2Web, WebTailBench).

For installation + the full reproducibility CLI, see the repo-root
[`README.md`](../README.md). Activate the **`fara_webeval`** conda env
before running anything below.

This document focuses on a single internal contract that every
benchmark, system, and verifier reads or writes: the **trajectory** —
i.e. the on-disk record of one agent run on one task.

## Trajectory format

Every executed task lives in its own directory under
`<out_url>/runs/<system.hash>/<model_prefix>/<user>/<benchmark.exec_hash>/<run_id>/traj/<task_id>/`,
e.g.:

```
/path/to/Fara/eval/runs/WebSurfer-fara-100-max_n_images-3/
  fara-7b/<user>/WebTailBench_hf/<run_id>/traj/<task_id>/
    web_surfer.log                 # newline-delimited JSON action+observation log
    <task_id>_final_answer.json    # FinalAnswer dump (final_answer, screenshots, token_usage)
    screenshot_1.png ... screenshot_N.png
    times.json                     # {start_time, end_time, duration} of the solver run
    core.log                       # webeval.core per-task log (Execution / Evaluation lifecycle)
    task_data.json                 # only present after the rubric verifier runs (see below)
    scores/
      <benchmark.eval_hash>.json   # {score: float, gpt_response_text: str|json}
```

A concrete example is checked in at
[`webeval/data/example_trajectory/`](data/example_trajectory/) — a
single WebTailBench AllTrails task (`alltrails_find_23`) with its
`web_surfer.log`, `alltrails_find_23_final_answer.json`,
`screenshot_{1..4}.png` frames, `times.json`, `core.log`,
`task_data.json` (written by the rubric verifier on re-eval), and the
`scores/mmrubric_0.8-5-3.json` rubric verdict (`score=1`). Point
`Trajectory.from_folder(...)` at that dir to see every field below
populated end-to-end.

### `web_surfer.log` (one JSON object per line)

Written by the `LogHandler` in `webeval/utils.py`, attached to the
`WebSurferLogger` inside `WebSurferSystem.get_answer()`. The handler
runs at `DEBUG` level so the `FaraAgent.{generate_model_call,
execute_action}` methods (`src/fara/fara_agent.py`) — which emit at
`logger.debug(...)` — actually flow through. Every line carries a
top-level `type` field (`LogHandler.emit` in `webeval/utils.py:124`).
In the current `FaraAgent` pipeline only two of them are actually
produced:

| `type`           | Source                                          | Key fields |
|------------------|-------------------------------------------------|---|
| `WebSurferEvent` | `FaraAgent.execute_action` (`src/fara/fara_agent.py:467`) | `timestamp`, `source`, `message`, `url`, `action`, `arguments`. The structured action event — one per tool call, with `action=<tool>` and `arguments=<dict>`. |
| `OtherEvent`     | `FaraAgent`'s raw `logger.debug(...)` strings (`fara_agent.py:403,415`) | `timestamp`, `type`, `message`. The `Thought #N: ...\nAction #N: executing tool '<tool>' with arguments {...}` and `Observation#N: ...` prints land here, because they're plain strings, not dataclasses, and `LogHandler.emit` falls through to its catch-all branch. |

Three more event dataclasses (`OrchestrationEvent`, `AgentEvent`,
`LLMCallEvent`) are declared in `webeval/systems/messages.py` /
`webeval/utils.py` and handled by `LogHandler.emit`, but have no
construction callsites in the current repo — they're reserved for
other solver systems / legacy trajectories and won't appear in a
fresh `FaraAgent` run.

`Trajectory.__init__` reads every line and either:

1. Uses each event's top-level `action` field directly (the
   `WebSurferEvent` shape), OR
2. If no event has an `action` field (the all-`OtherEvent` case), runs
   `parse_text_based_event` to extract `action` + `arguments` (with
   `thoughts`) from the `Thought #N: ... Action #N: executing tool …`
   text. This is how trajectories from older `WebSurferSystem` runs
   are recovered.

After parsing, `Trajectory.actions` is a list of JSON-encoded action
arg dicts (with `thoughts` stripped) and `Trajectory.thoughts` is the
parallel list of thought strings.

> **Gotcha**: if `web_surfer.log` is empty, `Trajectory.events == []`
> and `Trajectory.actions == []`. Downstream evaluators (e.g.
> `WebTailBenchBenchmark.evaluator`) treat that as
> `verifier_reasoning="No actions found in the trajectory"` and return
> score 0 **without** invoking MMRubricAgent. The fix is in
> `WebSurferSystem.get_answer()`, which now bumps the logger to `DEBUG`
> before the `FaraAgent` runs.

### `<task_id>_final_answer.json` (`FinalAnswer` dataclass)

Written by `WebSurferSystem.get_answer()` once the agent terminates or
hits `max_rounds`. Field reference (`webeval/trajectory.py:FinalAnswer`):

| Field            | Type                       | Notes |
|------------------|----------------------------|---|
| `final_answer`   | `str`                      | The agent's final response text. Defaults to `"<no_answer>"` — see the next section for what that means. |
| `env_state_json` | `str` (JSON)               | Parsed JSON dump of the final webpage `<pre>` element at `/finish` (synthetic envs only). |
| `env_state_raw`  | `str`                      | Raw text from that `<pre>` element (debugging / fallback if `env_state_json` parse failed). |
| `screenshots`    | `List[str]`                | Screenshot filenames captured during the run, **relative** to the trajectory dir if `is_rel_paths` is true (the default), else absolute. |
| `is_aborted`     | `bool`                     | True if the trajectory was killed mid-execution by an environment error. Aborted trajectories are typically retried up to `--max_error_task_retries` (see `webeval/core.py`). |
| `is_rel_paths`   | `bool`                     | Whether `screenshots` paths are relative to `trajectory.path`. New runs use `True`. |
| `token_usage`    | `Dict[str, RequestUsage]`  | Per-component LLM token usage. The example uses `{"FaraAgent": {"prompt_tokens": 23383, "completion_tokens": 1920}}` — the key is whichever component name `WebSurferSystem.get_answer()` attributes the call to. Aggregated via `RequestUsage.__add__`. |

Persisted via `FinalAnswer.save(path)`; loaded via `FinalAnswer.load(path)`.
`Trajectory.__init__` calls `FinalAnswer.load(...)` on the single
`*_final_answer.json` it finds in the dir (raises `ValueError` if 0
or >1 are present), reattaches the loaded `FinalAnswer` as
`trajectory.answer`, and exposes the screenshot list directly as
`trajectory.screenshots`. `trajectory.is_aborted` is just a
pass-through to `trajectory.answer.is_aborted`.

#### `final_answer == "<no_answer>"` is the load-bearing flag

`FinalAnswer` is constructed with `final_answer = "<no_answer>"` as the
default, and `WebSurferSystem.get_answer()` only **overwrites it with
the agent's actual answer string when the agent calls `terminate(...)`
within `--max_rounds` steps**. Three trajectory outcomes therefore look
different on disk:

| Outcome                                    | `is_aborted` | `final_answer`        | Notes |
|--------------------------------------------|--------------|-----------------------|---|
| Agent called `terminate(...)` within budget| `False`      | the model's response  | Only this case has a real string to score. |
| Agent never called `terminate`, hit `--max_rounds` | `False` | `"<no_answer>"`       | Trajectory ran to completion-by-cutoff; downstream is free to score the final state but the model itself produced no answer. |
| Run errored mid-execution (browser crash, timeout, …) | `True`  | `"<no_answer>"`       | Will be retried up to `--max_error_task_retries` (`webeval/core.py:run_eval_single_example`); only the final attempt's `_final_answer.json` is kept. |

**Filtering "actually completed" runs**: anywhere you want trajectories
that finished within step budget AND produced a real model answer, the
canonical check is

```python
candidate.answer.final_answer != "<no_answer>" and not candidate.is_aborted
```

This is what `webeval/post_eval_analysis.py` uses when computing
"average score across non-aborted, non-step-budget-exceeded
trajectories", and it's also why `WebTailBenchBenchmark.evaluator`
short-circuits with `verifier_reasoning='The last action must be
"terminate"'` for any trajectory whose last logged action is not
`terminate` — those are guaranteed to have `final_answer ==
"<no_answer>"` and therefore nothing the rubric judge can grade.

> **Auto-0 vs excluded**: two superficially similar cases are scored
> very differently.
>
> - **Over-budget** (`<no_answer>`, `is_aborted=False`): WebTailBench
>   short-circuits to `score=0` without calling the rubric judge,
>   writes it to `scores/<eval_hash>.json`, and **counts it as 0 in
>   the mean**.
> - **Aborted / errored mid-run** (`is_aborted=True`, loader fails,
>   or evaluator raises): returns `score=None`, no score file is
>   written, and every aggregator filters on `score is not None` —
>   so aborted trajectories are **excluded from all final metrics**
>   rather than counted as 0.

`screenshot_{i}.png` files keep accumulating regardless of how the
trajectory ended, so screenshot count alone is **not** a proxy for
"in budget" — always combine it with the `final_answer` check above.
Note: `trajectory.latest_screenshot` is a static convenience path
(`trajectory.path / "screenshot_scaled.png"`, see
`webeval/trajectory.py:131`) that may not exist on disk for every
run — the example directory, for instance, has only
`screenshot_1..4.png`.

### `times.json`

`{"start_time": <unix-float>, "end_time": <unix-float>, "duration":
<float-seconds>}`, written around the solver call in
`webeval/core.py:run_single_task` (`webeval/core.py:86-93`). Both
stamps are `time.time()` values (not ISO-8601); e.g. the example is
`{"start_time": 1762809276.0520103, "end_time": 1762809454.79363,
"duration": 178.74161958694458}`. `evaluate_single_example` reads
`duration` to populate `EvalResult.duration`.

### `scores/<benchmark.eval_hash>.json`

Written by `webeval/core.py:evaluate_single_example` after a successful
`Benchmark.evaluate_example()` call. Single writer, single shape across
all benchmarks (top-level `{score, gpt_response_text}`); the
benchmark-specific verdict lives inside `gpt_response_text`.

| Field               | Type             | Notes |
|---------------------|------------------|---|
| `score`             | `float` or `int` | Top-line success metric (0/1 for outcome-style judges; fraction for rubric-style judges). |
| `gpt_response_text` | `str` (often a JSON-encoded dict) | Free-form judge output. See per-benchmark table below. |

#### Where each benchmark's verdict lives

The score file is the **single source of truth for an evaluation
result**. `final_answer.json` is never overwritten by the verifier.
`task_data.json` is a separate dump the WebTailBench rubric verifier
writes alongside the score file (`benchmarks/webtailbench.py:346` →
`[Rubric] Saved rubric results to …/task_data.json`), so a fresh
solver-only run won't have one, but any trajectory that's been
re-scored — including the checked-in example — will. Re-running the
verifier (`--redo_eval` or `scripts/verify_trajectories.py`) rewrites
the score file in place and, for webtailbench, refreshes
`task_data.json` with the latest rubric payload.

| Benchmark | Score file path under `traj/<task_id>/` | `gpt_response_text` payload |
|---|---|---|
| `webvoyager` | `scores/gpt_eval.json` | gpt-4o judge text — verdict is `"SUCCESS"` / `"NOT SUCCESS"` parsed back to `score ∈ {0.0, 1.0}` (`benchmarks/webvoyager/webvoyager.py`). |
| `om2w` | `scores/<eval_method>-<threshold>.json` (e.g. `WebJudge_Online_Mind2Web_eval-3.json`) | o4-mini judge text — verdict via `extract_predication(...)` from the OnlineMind2Web judge methods (`benchmarks/om2w/om2w.py`). |
| `webtailbench` | `scores/mmrubric_<rubric_threshold>-<max_imgs>-<keypt>.json` | JSON-encoded dict assembled in `benchmarks/webtailbench/webtailbench.py:355-442`: `is_success` (int 0/1), `success_criterion` (`outcome` / `process` / `both`), `final_answer`, `outcome_success` (bool), `outcome_reasoning`, `outcome_primary_intent`, `rubric_is_success` (int), the `rubric_*` family forwarded from MMRubricAgent (`rubric_items`, `rubric_total_earned_points`, `rubric_total_max_points`, `rubric_all_scores_list`, `rubric_all_rubric_dicts`, `rubric_intermediate_mm_rubric_steps`, `rubric_outcome_verification`, `rubric_majority_vote_metadata`), and the error-taxonomy fields nested inside the rubric payload (`first_point_of_failure`, `is_ambiguous` / `ambiguity_codes`, `is_invalid` / `invalid_task_codes` — `mm_rubric_agent.py:392-406`). Top-level `score` equals `is_success`, which is driven by `--success`: `outcome` → `int(outcome_success)`, `process` → `rubric_is_success`, `both` → both. |
| `verify_trajectories.py` (stand-alone) | same path + shape as `webtailbench` | same Universal Verifier output. |

### `core.log`

Per-task log lines from the `webeval.core.<task_id>` logger. Useful
when a task hangs or errors and the rest of the pipeline keeps
moving. A run's `core.log` typically mixes:

- `[Execution <task_id>] Start / Trajectory is not complete. Reexecuting... / Completed / Error`
- BrowserBase plumbing: `Initializing BrowserBase session...`,
  `Connected to BrowserBase session: <url>`, `Closing browser...`
- Every `WebSurferEvent` event re-emitted as its dataclass
  `repr(...)` (so the same step shows up both here and in
  `web_surfer.log`, just unparsed)
- `[Evaluation <task_id>] Start / Loading from: <path> / Completed: score=<n>, duration=<seconds> / Error`
- `[Rubric] Saved rubric results to <path>/task_data.json` when the
  WebTailBench rubric verifier runs

The example's `core.log` shows the full sequence for one solve on
2025-11-10 plus three separate rubric re-eval passes on 2026-03-26,
all against the same trajectory directory.

### `task_data.json` (optional, rubric-verifier output)

Only written by the WebTailBench rubric verifier
(`benchmarks/webtailbench/webtailbench.py:346`), so trajectories that
have never been re-scored won't have one. When present, it's a large
JSON dump of the task's rubric/outcome state — everything MMRubricAgent
produced plus the task metadata it loaded. In the example,
`task_data.json` has 76 keys, including `task_summary`, `task_type`,
`rubric_score`, `verifier_agent_response`, `verifier_rubric`,
`start_timestamp`, `end_timestamp`, `token_usage`, `plan_list`,
`facts_list`, `observations_list`, `actions`, `actions_summary`, and
the boolean error-taxonomy flags (`did_web_surfing_fail`,
`web_surfing_stalled`, `encountered_captcha`, …). Treat this file as
diagnostic detail; the authoritative score still lives in
`scores/<eval_hash>.json`.

## `Trajectory` consumers

```python
from webeval.trajectory import Trajectory
traj = Trajectory.from_folder("/path/to/<task_id>/")
# Returns None if the dir is missing the answer file or the log can't be parsed.
traj.events                # list[dict] of parsed action/observation events
traj.actions               # list[str]  of JSON-encoded action-arg dicts
traj.thoughts              # list[str]  parallel to .actions
traj.screenshots           # list[Path] absolute paths to screenshot files
traj.answer                # FinalAnswer
traj.is_aborted            # bool (delegates to .answer.is_aborted)
traj.latest_screenshot     # convenience: trajectory.path / "screenshot_scaled.png"
```

Three places consume it today:

1. **Benchmark verifiers** (`webeval/benchmarks/*/<bench>.py`): each
   benchmark's `evaluator(task_data, candidate)` receives a
   `Trajectory` and returns `(score, gpt_response_text)`. WebTailBench
   wraps `MMRubricAgent` (the Universal Verifier) for this; webvoyager
   / om2w call their own GPT judges.
2. **`webeval/scripts/verify_trajectories.py`**: stand-alone parallel
   runner that points `MMRubricAgent` at any directory of
   `Trajectory`-shaped folders and writes per-task
   `scores/mmrubric_<…>.json`. Useful for re-scoring an existing
   eval run with new judge parameters.
3. **`webeval/post_eval_analysis.py`**: aggregates
   `_final_answer.json` + `scores/<…>.json` + counts of
   `WebSurferEvent` lines in `web_surfer.log` for run-level reporting.

## Where each file is written

| File                              | Writer                                                                                    |
|-----------------------------------|-------------------------------------------------------------------------------------------|
| `web_surfer.log`                  | `LogHandler` attached in `WebSurferSystem.get_answer()` (capturing `FaraAgent` log calls) |
| `<task_id>_final_answer.json`     | `WebSurferSystem.get_answer()` → `FinalAnswer.save()`                                     |
| `screenshot{i}.png`               | `FaraAgent.execute_action` (browser screenshots; one per action by default)               |
| `times.json`                      | `webeval/core.py:run_single_task`                                                         |
| `core.log`                        | `_logger = logger.getChild(task_id)` in `webeval/core.py:run_eval_single_example`         |
| `scores/<benchmark.eval_hash>.json` | `webeval/core.py:evaluate_single_example`                                                 |
| `scores/mmrubric_<…>.json`        | `webeval/scripts/verify_trajectories.py`                                                  |

---

### Overview (`webeval/src/webeval/benchmarks/webvoyager/README.md`)

https://github.com/MinorJerry/WebVoyager/blob/main/evaluation/auto_eval.py to add

---

### Overview (`webeval/src/webeval/benchmarks/om2w/impl/README.md`)

<h1 align="center"> Online-Mind2Web Benchmark </h1>

<p align="center">
  <a href="https://xuetianci.github.io/" style="text-decoration: none;">Tianci Xue<sup>,1</sup></a>, 
  <a href="https://x.com/weijian_qi" style="text-decoration: none;">Weijian Qi<sup>*,1</sup></a>,
  <a href="https://tnshi.com/" style="text-decoration: none;">Tianneng Shi<sup>*2</sup></a>,
  <a href="https://chanh.ee/" style="text-decoration: none;">Chan Hee Song<sup>1</sup></a>,
  <a href="https://boyugou.github.io/" style="text-decoration: none;">Boyu Gou<sup>1</sup></a>,
  <a href="https://dawnsong.io/" style="text-decoration: none;">Dawn Song<sup>,2</sup></a>,
  <a href="https://u.osu.edu/ihudas/people/" style="text-decoration: none;">Huan Sun<sup>†,1</sup></a>
  <a href="https://ysu1989.github.io/" style="text-decoration: none;">Yu Su<sup>†,1</sup></a>
</p>

<p align="center">
  <sup>1</sup>The Ohio State University, <sup>2</sup>University of California, Berkeley </br>
  <sub><sup>*</sup>Equal contribution, <sup>†</sup>Equal advising</sub>
</p>

<p align="center">
<a href="https://arxiv.org/abs/2504.01382">📃 Paper</a>
•
<a href="https://tiancixue.notion.site/An-Illusion-of-Progress-Assessing-the-Current-State-of-Web-Agents-1ac6cd2b9aac80719cd6f68374aaf4b4?pvs=4">📃 Blog</a>
•
<a href="https://huggingface.co/spaces/osunlp/Online_Mind2Web_Leaderboard" >🏆 Leaderboard</a>
•
<a href="https://huggingface.co/datasets/osunlp/Online-Mind2Web" >🤗 Data</a>
</p>


# Online-Mind2Web benchmark

## News
* [05/11/2025] Check out our updates in the [paper](https://arxiv.org/abs/2504.01382).
  * The performance of Claude Computer Use 3.7.
  * WebJudge(o4-mini) achieves high agreement (86%) with a low success rate gap (3.8%) compared with humans.
  * Release [WebJudge-7B](https://huggingface.co/osunlp/WebJudge-7B), a robust and reliable reward model for Reinforcement learning.

## Tasks
Online-Mind2Web includes 300 diverse tasks from 136 popular websites across various domains. It covers a diverse set of real-world user tasks, such as clothing, food, housing, and transportation, to evaluate web agents' performance in a real-world online environment.

## Update Tasks

We will regularly update Online-Mind2Web by replacing outdated or invalid tasks (e.g., due to website changes) to maintain its value as a rigorous benchmark for web agents. If you find any tasks are outdated, please reach out to us, and we will update them.

To ensure fair comparisons, we will aim to keep the updated tasks on the same websites as before and with a similar reference length. Additionally, once agent performance saturates on Online-Mind2Web, we will also revise simple tasks to preserve its long-term value.

# Automatic Evaluator via LLM-as-a-Judge (WebJudge)
To enhance the reliability and scalability of the evaluation process in online environments, We propose a more reliable automatic evaluation method called **WebJudge**, which consists of three parts. (1) Key Point Identification: The model is prompted to identify several key points necessary for completing the task, based on the given instruction and task description. (2) Key Screenshot Identification: Important screenshots are selected from the agent’s trajectory to retain relevant visual evidence while discarding uninformative frames. (3) Outcome Judgment: Output the judgement result based on the task description, key points, key screenshots, and the action history. Our method preserves critical intermediate screenshots while mitigating the token overload issue.

<p align="center">
  <img src="./images/WebJudge.jpg" width="100%" alt="pipeline">
</p>

# Results

## Comparison against Existing Evaluation Methods on Online-Mind2Web
<table>
<tr>
  <th>Model</th>
  <th>Auto-Eval</th>
  <td>SeeAct</td>
  <td>Agent-E</td>
  <td>Browser Use</td>
  <td>Claude 3.5 </td>
  <td>Claude 3.7</td>
  <td>Operator</td>
  <th>Avg AR</th>
</tr>
<tr>
  <th rowspan="4">GPT-4o</th>
  <td>Autonomous Eval</td>
  <td>84.7</td>
  <td>85.0</td>
  <td>76.0</td>
  <td>83.7</td>
  <td>75.5</td>
  <td>71.7</td>
  <td>79.4</td>
</tr>
<tr>
  <td>AgentTrek Eval</td>
  <td>73.0</td>
  <td>64.3</td>
  <td>63.3</td>
  <td>--</td>
  <td>--</td>
  <td>--</td>
  <td>66.9</td>
</tr>
<tr>
  <td>WebVoyager</td>
  <td>--</td>
  <td>75.3</td>
  <td>71.3</td>
  <td>74.0</td>
  <td>72.0</td>
  <td>76.7</td>
  <td>73.9</td>
</tr>
<tr>
  <td>WebJudge</td>
  <td>86.7</td>
  <td>86.0</td>
  <td>81.4</td>
  <td>86.3</td>
  <td>79.1</td>
  <td>81.8</td>
  <td><b>83.6</b></td>
</tr>

<tr>
  <th rowspan="3">o4-mini</th>
  <td>Autonomous Eval</td>
  <td>79.7</td>
  <td>85.7</td>
  <td>86.0</td>
  <td>84.3</td>
  <td>68.0</td>
  <td>73.3</td>
  <td>79.5</td>
</tr>
<tr>
  <td>WebVoyager</td>
  <td>--</td>
  <td>80.3</td>
  <td>79.0</td>
  <td>81.7</td>
  <td>74.3</td>
  <td>78.3</td>
  <td>78.7</td>
</tr>
<tr>
  <td>WebJudge</td>
  <td>85.3</td>
  <td>86.3</td>
  <td>89.3</td>
  <td>87.0</td>
  <td>82.3</td>
  <td>83.7</td>
  <td><b>85.7</b></td>
</tr>

<tr>
  <th></th>
  <td>WebJudge-7B</td>
  <td>86.0</td>
  <td>87.3</td>
  <td>88.3</td>
  <td>89.7</td>
  <td>84.3</td>
  <td>86.3</td>
  <td><b>87.0</b></td>
</tr>
</table>
WebJudge powered by GPT-4o and o4-mini consistently achieves the highest agreement, with averages of 83.6% and 85.7%, respectively. Meanwhile, WebJudge-7B even outperforms o4-mini, reaching a high agreement with human judgment of 87%.


## Excellent generalization capabilities on [AgentRewardBench](https://agent-reward-bench.github.io/) (5 OOD benchmarks)
| **Methods** | **AB** | **VWA** | **WA** | **Work** | **Wk++** | **Overall** |
|--------------|--------|--------|--------|----------|----------|--------------|
| *Rule-based** | 25.0 | **85.2** | 79.0 | 100.0 | 83.3 | 83.8 |
| Autonomous Eval* | 83.3 | 61.2 | 67.6 | 96.4 | 59.3 | 67.6 |
| GPT-4o (A11y Tree)* | 77.8 | 63.0 | 70.2 | 94.6 | 63.0 | 69.8 |
| WebJudge (GPT-4o) | 66.7 | 69.8 | 72.6 | 92.3 | 75.0 | 73.7 |
| WebJudge-7B | 80.0 | 66.7 | 77.5 | 100.0 | 70.0 | 75.7 |
| WebJudge (o4-mini) | **100.0** | 74.5 | **81.2** | **100.0** | **90.0** | **82.0** |

WebJudge significantly outperforms existing methods, achieving impressive overall precision of 73.7% 75.7% and 82.0% on WebArena (WA), VisualWebArena (VWA), AssistantBench (AB), WorkArena (Work) and WorkArena++ (Wk++) across 1302 trajectories.

The high precision suggests that WebJudge holds potential as a robust and scalable reward model for downstream applications such as Rejection Sampling Fine-Tuning, Reflection, and Reinforcement Learning.

# Model Release
We have released the fine-tuned [WebJudge-7B](https://huggingface.co/osunlp/WebJudge-7B) weights, which are now available on Hugging Face.

# Setup Environment

Create a conda environment and install dependencies:
```
conda create -n Online_Mind2Web python=3.11
conda activate Online_Mind2Web
pip install -r requirements.txt
```

# Evaluation
You can run the provided example evaluation script directly to perform the evaluation. Adjust the "mode" parameter to choose among various auto-eval methods.
```bash
bash ./script/eval.sh
```

## Important Notes for Reliable Evaluation on Online-Mind2Web:
> [!IMPORTANT]
> - **Start from the specified websites, not Google Search**:To enable fair comparisons, please ensure that each task starts from the specified website in our benchmark. Starting from Google Search or alternative websites can lead agents to use different websites to solve the task, resulting in varying difficulty levels and potentially skewed evaluation results.
> - **Include only factual actions, not agent outputs**: The action history should contain only the factual actions taken by the agent to complete the task (e.g., clicking elements and Typing text). Do not include the final response or any other agent's outputs, as they may contain hallucinated content and result in a high rate of false positives.
> - **Use o4-mini for WebJudge**: WebJudge powered by o4-mini demonstrates a higher alignment with human judgment, achieving an average agreement rate of 85.7% and maintaining a narrow success rate gap of just 3.8%. Therefore, please use o4-mini as the backbone for automatic evaluation.

# Evaluation Results

In certain scenarios, testing on the full Online-Mind2Web dataset may not be feasible due to cost, privacy, or legal constraints. To facilitate fair and apple-to-apple comparisons, we release both our human evaluation labels and auto-eval details.

- **Human Evaluation**: Task-level human evaluation labels are provided in the [file](https://github.com/OSU-NLP-Group/Online-Mind2Web/tree/main/data/evaluation_results/online_mind2web_evaluation_results/human_label.json).
- **Auto-Evaluation**: The results of WebJudge are available in the [folder](https://github.com/OSU-NLP-Group/Online-Mind2Web/tree/main/data/evaluation_results/online_mind2web_evaluation_results).

## 📚 Citation

Note: Online-Mind2Web is derived from the original Mind2Web dataset. We kindly ask that you cite both the original and this work when using or referencing the data.
```
@article{xue2025illusionprogressassessingcurrent,
      title={An Illusion of Progress? Assessing the Current State of Web Agents}, 
      author={Tianci Xue and Weijian Qi and Tianneng Shi and Chan Hee Song and Boyu Gou and Dawn Song and Huan Sun and Yu Su},
      year={2025},
      eprint={2504.01382},
      archivePrefix={arXiv},
      primaryClass={cs.AI},
      url={https://arxiv.org/abs/2504.01382}, 
}

@inproceedings{deng2023mind2web,
 author = {Deng, Xiang and Gu, Yu and Zheng, Boyuan and Chen, Shijie and Stevens, Sam and Wang, Boshi and Sun, Huan and Su, Yu},
 booktitle = {Advances in Neural Information Processing Systems},
 editor = {A. Oh and T. Naumann and A. Globerson and K. Saenko and M. Hardt and S. Levine},
 pages = {28091--28114},
 publisher = {Curran Associates, Inc.},
 title = {Mind2Web: Towards a Generalist Agent for the Web},
 url = {https://proceedings.neurips.cc/paper_files/paper/2023/file/5950bf290a1570ea401bf98882128160-Paper-Datasets_and_Benchmarks.pdf},
 volume = {36},
 year = {2023}
}
```

---

### Overview (`webeval/src/webeval/benchmarks/om2w/impl/data/README.md`)

## Example

You can refer to the [example](https://github.com/OSU-NLP-Group/Online-Mind2Web/tree/main/data/example/fb7b4f784cfde003e2548fdf4e8d6b4f) format when conducting auto-eval. For each task, the result should be stored in a folder named as its `task_id`, containing :

- `trajectory/`: Stores screenshots of each step.
- `result.json`: Task metadata and action history.


## 🧠 Human Labels

The file `human_label.json` provides human evaluation labels for each task across different agents. The meaning of labels represent as following:

- `0`: ❌ **Failure** – The agent did **not** successfully complete the task.
- `1`: ✅ **Success** – The agent **successfully** completed the task.
- `2`: 🚫 **Not Executable** – The agent was **unable to execute** the task due to external or system-related limitations.

## ℹ️ Details on Label 2

The label 2 indicates that the agent could not execute the task at all. The specific reasons vary by agent:

- **SeeAct**: Some tasks raise internal bugs when the agent extracts elements from the web page.
- **Operator**: Certain websites (e.g., Reddit) are inaccessible, preventing task execution.
- **Claude Computer Use 3.7**: Due to updates on the websites, a few tasks became outdated during the testing phase..
- **Agent-E** and **Browser Use**: Label 2 typically corresponds to tasks blocked by **CAPTCHAs**. There are only **two** tasks for Agent-E and **one** task for Browser Use.

## Note
The results on the leaderboard are averaged over three runs, so there may be slight differences compared to the auto-eval results shown here.

---

### Eval Reproducibility (`docs/eval_reproducibility.md`)

# Eval Reproducibility (webeval)

> **Note:** This document covers the `webeval/` pipeline that produced the
> published Fara-7B benchmark numbers (WebVoyager, Online-Mind2Web,
> WebTailBench). It predates the Fara-1.5 release and will be updated as the
> repo is refactored to the Fara-1.5 evaluation stack. For the trajectory
> on-disk format, see [`webeval/README.md`](../webeval/README.md).

Agentic evaluations on live websites present unique challenges due to day-to-day changes. We implement several measures to ensure reliable and comparable evaluations:

**BrowserBase Integration**
We employ BrowserBase to manage browser session hosting, enabling reliable browser instance management.

**Time-sensitive Task Updates**
Tasks in benchmarks like WebVoyager can become stale or impossible. We:
- Removed ~48 impossible tasks from the original WebVoyager benchmark
- Updated ~50 tasks with future dates to keep them achievable
- Example: *"Search for a hotel in Bali from Jan 1 to Jan 4, 2024"* → *"Search for a hotel in Bali from Jan 1 to Jan 4, 2026"*
- Our updated WebVoyager benchmark is available at `webeval/data/webvoyager/WebVoyager_data_08312025.jsonl`

**Environment Error Handling**
Browser errors (connection drops, page timeouts) are handled robustly:
- Trajectories are retried up to 5 times when environment errors occur
- Complete yet incorrect trajectories are never retried
- Each retry starts with a fresh browser session, with no retained state

**Step Budget**
Each trajectory is capped at a maximum of 100 actions across all online benchmarks. Trajectories exceeding this budget without choosing to stop are considered incorrect.

## WebEval Package Installation

```bash
conda create --name fara_webeval python=3.12
conda activate fara_webeval

# Install fara package (with vllm extras for GPU hosting)
pip install -e .[vllm]

# Install webeval
cd webeval
pip install -e .

# Install playwright
playwright install
```

The webeval package no longer depends on `autogen-core` / `autogen-ext` —
all chat completion clients are vendored under `webeval/src/webeval/oai_clients/`
(see `GracefulRetryClient`, `OpenAIClientWrapper`, `AzureOpenAIClientWrapper`,
etc.). You no longer need to clone or install the autogen submodule.

> **Always activate the `fara_webeval` env before running any of the eval
> scripts below.** It pins `vllm==0.10.0` + `torch==2.7.1`; running with
> a newer `vllm` (≥ 0.19) under `torch` ≥ 2.10 trips a known
> `torch._dynamo.symbolic_convert` crash during CUDA-graph capture, which
> can be worked around with `--enforce_eager` but at a meaningful
> throughput cost. Stick to the pinned env.

## Running Evaluations

Navigate to the scripts directory:

```bash
cd webeval/scripts
```

Make sure you set a valid OpenAI GPT-4o endpoint in `endpoint_configs_gpt4o/dev` in order to run the WebVoyager LLM-as-a-judge! 

**Option 1: Self-hosted vLLM**

```
/* Detailed source-code truncated for AI context efficiency. */
```

**Option 2: Azure Foundry Deployment**

Deploy [Fara1.5-9B on Foundry endpoint(s)](https://ai.azure.com/catalog/models/Fara1.5-9B), then place endpoint URLs and keys in JSONs under `endpoint_configs/`:

```bash
python webvoyager.py --model_endpoint ../../endpoint_configs/ --eval_oai_config ../endpoint_configs_gpt4o/dev/ --out_url /path/to/save/eval/files --processes 1 --run_id 1_endpoint --max_rounds 100
python om2w.py --model_endpoint ../../endpoint_configs/ --eval_oai_config ../endpoint_configs_o4/dev/ --eval_model o4-mini --out_url /path/to/save/eval/files --processes 1 --run_id 1_endpoint --max_rounds 100
python webtailbench.py --model_endpoint ../../endpoint_configs/ --eval_oai_config ../../endpoint_configs/judge_active/prod --judge_eval_model gpt-5.2 --judge_o4_eval_model o4-mini --out_url /path/to/Fara/eval --processes 1 --run_id 1_endpoint --max_rounds 100
```

### Notes


- We use the same LLM-as-a-judge prompts and model (GPT-4o) as WebVoyager, hence the `--eval_oai_config` argument
- Set `--browserbase` for browser session management (requires exported API key and project ID environment variables)
- Avoid overloading a single vLLM deployment with more than ~10 concurrent processes due to known issues
- See debugging output in `fara/webeval/scripts/stdout.txt`

---

## Analyzing Evaluation Results

### Evaluation Output Structure

Evaluation results are stored under `--out_url` in folders organized by:
- Model name
- Dataset
- Username
- Run ID

Example path:
```
/runs/WebSurfer-fara-100-max_n_images-3/fara1.5-9b/<username>/WebVoyager_WebVoyager_data_08312025.jsonl/<run_id>
```

Each evaluation folder contains:
- `gpt_eval/` - LLM-as-a-judge evaluation results
- `traj/` - Per-task trajectory subdirectories containing:
  - `*-final_answer.json` (e.g., `Amazon--1_final_answer.json`) - `<no_answer>` indicates abortion or step budget exceeded
  - `scores/*_eval.json` - LLM judge scores (`gpt_eval.json` for WebVoyager, `WebJudge_Online_Mind2Web_eval-3.json` for Online-Mind2Web)
  - `web_surfer.log` - Action history and errors
  - `screenshot_X.png` - Screenshots captured before each action X
  - `times.json` - contains start and end times of task
  - `core.log` - contains high level logs like if the trajectory needs to be started or is already cached/done, the evaluation score, duration, and errors encountered

### Running Analysis

Use the analysis notebook to compute metrics:

```bash
cd webeval/scripts/analyze_eval_results/
jupyter notebook analyze.ipynb
```

The script:
- Identifies trajectories aborted mid-execution and diagnostic reasons
- Computes average scores across non-aborted trajectories
- Distinguishes between aborted trajectories (errors during sampling) and completed trajectories (with terminate() call or step budget exceeded)

To re-run failed tasks, execute the evaluation script again with the same `run_id` and `username` - it will skip non-aborted tasks.

<details>
<summary>Example WebVoyager GPT Eval Result</summary>

```json
{
  "score": 1.0,
  "gpt_response_text": "To evaluate the task, we need to verify if the criteria have been met:\n\n1. **Recipe Requirement**: A vegetarian lasagna recipe with zucchini and at least a four-star rating.\n\n2. **Search and Results**:\n   - The screenshots show that the search term used was \"vegetarian lasagna zucchini.\"\n   - Among the search results, \"Debbie's Vegetable Lasagna\" is prominently featured.\n   \n3. **Evaluation of the Recipe**:\n   - Rating: \"Debbie's Vegetable Lasagna\" has a rating of 4.7, which satisfies the requirement of being at least four stars.\n   - The presence of zucchini in the recipe is implied through the search conducted, though the screenshots do not explicitly show the ingredients list. However, the result response confirms the match to the criteria.\n\nGiven the information provided, the task seems to have fulfilled the requirement of finding a vegetarian lasagna recipe with zucchini and a four-star rating or higher. \n\n**Verdict: SUCCESS**"
}
```

</details>

<details>
<summary>Example of web_surfer.log (action history)</summary>

```
/* Detailed source-code truncated for AI context efficiency. */
```
</details>

---

--- METRICS ---
- Files Extracted: 6
- Estimated Token Budget: ~13826 tokens
- Canonical Reference: https://codewiki.google/github.com/microsoft/fara
