Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 6 additions & 21 deletions src/openai/types/evals/__init__.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,7 @@
# File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details.

from __future__ import annotations

from .eval_api_error import EvalAPIError as EvalAPIError
from .run_list_params import RunListParams as RunListParams
from .run_create_params import RunCreateParams as RunCreateParams
from .run_list_response import RunListResponse as RunListResponse
from .run_cancel_response import RunCancelResponse as RunCancelResponse
from .run_create_response import RunCreateResponse as RunCreateResponse
from .run_delete_response import RunDeleteResponse as RunDeleteResponse
from .run_retrieve_response import RunRetrieveResponse as RunRetrieveResponse
from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource as CreateEvalJSONLRunDataSource
from .create_eval_completions_run_data_source import (
CreateEvalCompletionsRunDataSource as CreateEvalCompletionsRunDataSource,
)
from .create_eval_jsonl_run_data_source_param import (
CreateEvalJSONLRunDataSourceParam as CreateEvalJSONLRunDataSourceParam,
)
from .create_eval_completions_run_data_source_param import (
CreateEvalCompletionsRunDataSourceParam as CreateEvalCompletionsRunDataSourceParam,
from .openeval import (
OpenEvalItem as OpenEvalItem,
from_openeval as from_openeval,
to_openeval as to_openeval,
)
Comment on lines +1 to 5

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve existing evals type exports

This replacement leaves openai.types.evals exporting only the new OpenEval helpers, so documented and in-repo imports such as from openai.types.evals import RunCreateResponse in tests/api_resources/evals/test_runs.py now fail for users of the evals runs API. Please add the new helpers without removing the generated eval response/param exports.

AGENTS.md reference: AGENTS.md:L5-L8

Useful? React with 👍 / 👎.

Comment on lines +1 to 5

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve existing evals type exports

This replacement leaves openai.types.evals exporting only the new OpenEval helpers, so documented and in-repo imports such as from openai.types.evals import RunCreateResponse in tests/api_resources/evals/test_runs.py now fail for users of the evals runs API. Please add the new helpers without removing the generated eval response/param exports.

Useful? React with 👍 / 👎.


__all__ = ["OpenEvalItem", "from_openeval", "to_openeval"]
62 changes: 62 additions & 0 deletions src/openai/types/evals/openeval.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# File generated for OpenEval dataset import/export support.

from typing import Any, Dict, List, Optional
from typing_extensions import TypedDict

__all__ = ["OpenEvalItem", "from_openeval", "to_openeval"]


class OpenEvalMessage(TypedDict, total=False):
role: str
content: str


class OpenEvalItem(TypedDict, total=False):
id: Optional[str]
input: List[OpenEvalMessage]
expected_output: Optional[str]
metadata: Optional[Dict[str, Any]]


def from_openeval(item: OpenEvalItem) -> Dict[str, Any]:
"""
Convert an OpenEval dataset item into OpenAI Chat Completion messages format.
"""
messages: List[Dict[str, Any]] = []
for msg in item.get("input", []):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept scalar OpenEval inputs

OpenEval/EvalPort JSONL rows commonly use scalar input values such as {'input': 'What is 2+2?'}, but this loop assumes every input entry is a message dict. In that valid case Python iterates the prompt characters and msg.get(...) raises AttributeError, so the import helper cannot read standard single-prompt datasets; please branch on str or turn arrays before treating entries as dicts.

Useful? React with 👍 / 👎.

messages.append({
"role": msg.get("role", "user"),
"content": msg.get("content", ""),
})

result: Dict[str, Any] = {"messages": messages}
if item.get("id"):
result["id"] = item["id"]
if item.get("expected_output"):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve empty expected outputs

When a dataset case expects an empty string, for example asserting that the model should produce no text, this truthiness check drops expected_output entirely. Downstream graders then see no reference output rather than ''; match the export path and preserve values that are present but falsy.

Useful? React with 👍 / 👎.

result["expected_output"] = item["expected_output"]
if item.get("metadata"):
result["metadata"] = item["metadata"]
return result


def to_openeval(
messages: List[Dict[str, Any]],
id: Optional[str] = None,
expected_output: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None,
) -> OpenEvalItem:
"""
Export OpenAI Chat Completion messages and metadata into OpenEval dataset item format.
"""
input_messages: List[OpenEvalMessage] = [
{"role": str(msg.get("role", "user")), "content": str(msg.get("content", ""))}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve structured chat message content

When exporting multimodal Chat Completions messages, content can be a list of content-part dictionaries, but this casts it through str(...) and writes a Python repr instead of preserving the structured JSON. Those exported eval rows cannot be round-tripped back into Chat Completions or consumed by tools expecting real content parts, so keep non-string content as structured data rather than stringifying it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve tool-call fields when exporting conversations

When the chat history contains tool/function-call messages, this export silently keeps only role and content. For example, a {"role": "tool", "tool_call_id": "call_1", ...} message round-trips through to_openeval()/from_openeval() without tool_call_id, but the SDK's ChatCompletionToolMessageParam requires that field, so exported agent/tool eval datasets produce messages that cannot be sent back to Chat Completions. Please preserve the remaining Chat Completion message fields or reject unsupported roles instead of stripping them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Emit schema-valid OpenEval inputs

For any normal chat message list, to_openeval() writes input as an array of {role, content} objects. The OpenEval/EvalPort TestCase schema only accepts input as a single string or an array of strings, so even the new test_to_openeval_conversion fixture would fail validation before graders are considered. Export the prompt text in the standard shape, or use a documented extension, rather than Chat Completions message objects.

Useful? React with 👍 / 👎.

for msg in messages
]
item: OpenEvalItem = {"input": input_messages}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Emit grader references in exports

When callers use to_openeval() to write a dataset, the returned object starts as only {'input': ...} and the function has no way to add graders, which are required on OpenEval/EvalPort TestCase rows. The resulting JSONL cannot be consumed or validated as OpenEval unless callers mutate every item afterward, so the helper should accept and emit grader references or export a suite with them.

Useful? React with 👍 / 👎.

if id is not None:
item["id"] = id
if expected_output is not None:
item["expected_output"] = expected_output
if metadata is not None:
item["metadata"] = metadata
return item
23 changes: 23 additions & 0 deletions tests/test_openeval.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from openai.types.evals import OpenEvalItem, from_openeval, to_openeval


def test_from_openeval_conversion() -> None:
item: OpenEvalItem = {
"id": "eval-1",
"input": [{"role": "user", "content": "Hello world"}],
"expected_output": "Hi there!",
"metadata": {"task": "test"},
}
converted = from_openeval(item)
assert converted["id"] == "eval-1"
assert converted["messages"] == [{"role": "user", "content": "Hello world"}]
assert converted["expected_output"] == "Hi there!"
assert converted["metadata"] == {"task": "test"}


def test_to_openeval_conversion() -> None:
messages = [{"role": "user", "content": "Hello"}]
exported = to_openeval(messages, id="eval-2", expected_output="World")
assert exported["id"] == "eval-2"
assert exported["input"] == [{"role": "user", "content": "Hello"}]
assert exported["expected_output"] == "World"