From dc3941e331eed6d4f32e3a74cecc84f43038bbdd Mon Sep 17 00:00:00 2001 From: Utsab Dahal <134686066+utsab345@users.noreply.github.com> Date: Thu, 2 Oct 2025 07:30:58 +0545 Subject: [PATCH] fix: prevent JSON content from being added multiple times during retries (#1255) --- rdagent/core/experiment.py | 9 ++++----- rdagent/oai/backend/base.py | 5 ++++- test/oai/test_base.py | 23 +++++++++++++++++++++++ 3 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 test/oai/test_base.py diff --git a/rdagent/core/experiment.py b/rdagent/core/experiment.py index a84159be..f9dac480 100644 --- a/rdagent/core/experiment.py +++ b/rdagent/core/experiment.py @@ -13,7 +13,7 @@ from collections.abc import Sequence from copy import deepcopy from dataclasses import dataclass from pathlib import Path -from typing import TYPE_CHECKING, Any, Generic, List, TypeVar +from typing import TYPE_CHECKING, Any, Generic, TypeVar from rdagent.core.conf import RD_AGENT_SETTINGS from rdagent.core.evaluation import Feedback @@ -48,12 +48,11 @@ class AbsTask(ABC): """ -class UserInstructions(List[str]): +class UserInstructions(list[str]): def __str__(self) -> str: if self: return ("\nUser Instructions (Top priority!):\n" + "\n".join(f"- {ui}" for ui in self)) if self else "" - else: - return "" + return "" class Task(AbsTask): @@ -69,7 +68,7 @@ class Task(AbsTask): self.user_instructions = user_instructions def get_task_information(self) -> str: - return f"Task Name: {self.name}\nDescription: {self.description}{str(self.user_instructions)}" + return f"Task Name: {self.name}\nDescription: {self.description}{self.user_instructions!s}" def __repr__(self) -> str: return f"<{self.__class__.__name__} {self.name}>" diff --git a/rdagent/oai/backend/base.py b/rdagent/oai/backend/base.py index cf0512a1..79664b9c 100644 --- a/rdagent/oai/backend/base.py +++ b/rdagent/oai/backend/base.py @@ -597,9 +597,12 @@ class APIBackend(ABC): new_messages = deepcopy(messages) # Loop to get a full response try_n = 6 + # Before retry loop, initialize the flag + json_added = False for _ in range(try_n): # for some long code, 3 times may not enough for reasoning models - if response_format == {"type": "json_object"} and add_json_in_prompt: + if response_format == {"type": "json_object"} and add_json_in_prompt and not json_added: self._add_json_in_prompt(new_messages) + json_added = True response, finish_reason = self._create_chat_completion_inner_function( messages=new_messages, response_format=response_format, diff --git a/test/oai/test_base.py b/test/oai/test_base.py new file mode 100644 index 00000000..eb04b2b1 --- /dev/null +++ b/test/oai/test_base.py @@ -0,0 +1,23 @@ +import pytest + + +class MockBackend: + def __init__(self): + self.messages = [] + + def _add_json_in_prompt(self, new_messages): + self.messages.append("JSON_ADDED") + + +def test_json_added_once(): + backend = MockBackend() + try_n = 3 + json_added = False + new_messages = ["msg1"] + + for _ in range(try_n): + if not json_added: + backend._add_json_in_prompt(new_messages) + json_added = True + + assert backend.messages.count("JSON_ADDED") == 1