Skip to content

feat(evals): add cancel_event to Eval and EvalAsync - #881

Merged
Abhijeet Prasad (AbhiPrasad) merged 2 commits into
mainfrom
abhi/python-sdk-pr-equivalent-dbdc0116
Oct 5, 2026
Merged

Abhijeet Prasad (AbhiPrasad) merged 2 commits into
mainfrom
abhi/python-sdk-pr-equivalent-dbdc0116

Conversation

@AbhiPrasad

@AbhiPrasad Abhijeet Prasad (AbhiPrasad) commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

Cancel an evaluation

EvalAsync and Eval accept an optional cancel_event: threading.Event. Keep a reference to the event and call set() when the evaluation should stop. You can also set timeout in seconds.

EvalAsync

import asyncio
import threading

from braintrust import EvalAsync

cancel_event = threading.Event()

async def task(prompt):
    return await generate_answer(prompt)

evaluation = asyncio.create_task(
    EvalAsync(
        "my-project",
        data=[{"input": "What is 2+2?"}],
        task=task,
        scores=[],
        cancel_event=cancel_event,
        timeout=30,
    )
)

# Later, when the user chooses Stop:
cancel_event.set()

try:
    await evaluation
except asyncio.CancelledError:
    pass  # Stopped by cancel_event.set()
except asyncio.TimeoutError:
    pass  # Stopped by timeout

Tasks do not need to inspect the event to receive async cancellation. Cancelling the asyncio.Task running EvalAsync also stops the evaluation and sets its event.

Eval

import threading

from braintrust import Eval

cancel_event = threading.Event()

def on_stop():
    cancel_event.set()

# Have another thread call on_stop() while Eval blocks.
Eval(
    "my-project",
    data=cases,
    task=sync_task,
    scores=[],
    cancel_event=cancel_event,
    timeout=30,
)

A synchronous task already running in a thread cannot be forcibly stopped. It can check hooks.cancel_event.is_set() to stop sooner; otherwise the evaluation waits for it to finish. This can make cancellation take longer than timeout.

For a long-running synchronous loop, checking the hook is optional:

def sync_task(items, hooks):
    results = []
    for item in items:
        if hooks.cancel_event.is_set():
            break
        results.append(process(item))
    return results
flowchart TD
    A["EvalAsync or Eval"] --> B{"Stop requested?"}
    B -- "cancel_event.set()" --> C["Stop starting queued trials"]
    B -- "timeout" --> C
    C --> D["Running async tasks receive cancellation"]
    C --> E["Running sync tasks can check hooks.cancel_event"]
    D --> F["Wait for running work to finish cleanup"]
    E --> F
    F --> G["Raise asyncio.CancelledError or asyncio.TimeoutError"]
Loading

An event that is already set prevents trials from starting. A timeout also sets the supplied event.

Accept a threading.Event in both eval entry points and expose it through task
hooks. On cancellation, skip queued trials, cancel async work, and wait for
running tasks and scorers before raising.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-05T22:25:14.482238Z 3c3f2be PR opened
ℹ️ About Codex in GitHub

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

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

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

Copy link
Copy Markdown

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: 3c3f2be41e

ℹ️ 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 (@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 (@codex) address that feedback".

Comment thread py/src/braintrust/framework.py Outdated
@AbhiPrasad
Abhijeet Prasad (AbhiPrasad) merged commit 964b6eb into main Oct 5, 2026
83 checks passed
@AbhiPrasad
Abhijeet Prasad (AbhiPrasad) deleted the abhi/python-sdk-pr-equivalent-dbdc0116 branch October 5, 2026 23:14
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