Skip to content

Conversation

@ProKil
Copy link
Member

@ProKil ProKil commented Oct 13, 2024

Closes #229

πŸ“‘ Description

This PR gives an example of simulating realtime conversation between agents in sotopia and aact.

βœ… Checks

  • My pull request adheres to the code style of this project
  • My code requires changes to the documentation
  • I have updated the documentation as required
  • All the tests have passed
  • Branch name follows type/descript (e.g. feature/add-llm-agents)
  • Ready for code review

β„Ή Additional Information


Note

Adds experimental realtime conversation examples and updates core Sotopia components with supporting server changes, tests, and mypy CI.

  • Examples (experimental realtime):
    • Add new realtime examples and utilities: examples/experimental/realtime/{audio_mixer.py,input_node.py,realtime_websocket.py}.
    • Add configuration files: realtime_chat.toml, realtime_chat_human_in_the_loop.toml, speaker_listener.toml and a readme.md.
  • Core/logic updates:
    • Enhance agents and messaging: sotopia/agents/llm_agent.py, sotopia/messages/message_classes.py.
    • Update environment orchestration: sotopia/envs/{evaluators.py,parallel.py}.
    • Refine generation pipeline: sotopia/generation_utils/{generate.py,output_parsers.py}.
    • Server adjustments in sotopia/server.py.
  • Tooling/Config:
    • Add MyPy workflow .github/workflows/mypy.yml.
    • Update project config pyproject.toml.
  • Tests:
    • Add/expand tests for API and core: tests/api/test_fastapi.py, tests/envs/{test_evaluators.py,test_parallel.py}, tests/generation_utils/test_generation.py, with shared setup in tests/conftest.py.

Written by Cursor Bugbot for commit ab61a2b. This will update automatically on new commits. Configure here.

@codecov
Copy link

codecov bot commented Oct 13, 2024

Codecov Report

❌ Patch coverage is 82.90909% with 47 lines in your changes missing coverage. Please review.
βœ… Project coverage is 74.92%. Comparing base (0def793) to head (ab61a2b).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
sotopia/generation_utils/generate.py 85.43% 15 Missing ⚠️
tests/conftest.py 87.85% 13 Missing ⚠️
sotopia/messages/message_classes.py 40.00% 12 Missing ⚠️
sotopia/envs/parallel.py 69.23% 4 Missing ⚠️
sotopia/generation_utils/output_parsers.py 72.72% 3 Missing ⚠️
@@            Coverage Diff             @@
##             main     #234      +/-   ##
==========================================
+ Coverage   74.02%   74.92%   +0.89%     
==========================================
  Files          72       72              
  Lines        4628     4821     +193     
==========================================
+ Hits         3426     3612     +186     
- Misses       1202     1209       +7     
Files with missing lines Coverage Ξ”
sotopia/agents/llm_agent.py 48.45% <100.00%> (+3.79%) ⬆️
sotopia/envs/evaluators.py 96.45% <100.00%> (+0.05%) ⬆️
sotopia/server.py 41.20% <ΓΈ> (ΓΈ)
tests/api/test_fastapi.py 98.33% <100.00%> (ΓΈ)
tests/envs/test_evaluators.py 100.00% <100.00%> (ΓΈ)
tests/envs/test_parallel.py 100.00% <100.00%> (ΓΈ)
tests/generation_utils/test_generation.py 100.00% <100.00%> (ΓΈ)
sotopia/generation_utils/output_parsers.py 70.11% <72.72%> (+0.23%) ⬆️
sotopia/envs/parallel.py 80.18% <69.23%> (-0.39%) ⬇️
sotopia/messages/message_classes.py 53.17% <40.00%> (-3.69%) ⬇️
... and 2 more

... and 1 file with indirect coverage changes

πŸš€ New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

},
)
await self.websocket.__aenter__()
await self.websocket.send(
Copy link

Choose a reason for hiding this comment

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

Bug: WebSocket connection entered twice

self.websocket = await connect(...) already yields an active ClientConnection in websockets>=13. Calling await self.websocket.__aenter__() again is inconsistent with the API and can raise at runtime or leave the connection in an unexpected state, breaking the realtime node initialization.

Fix in CursorΒ Fix in Web

for stream in stream_samples:
mixed_samples += stream
mixed_samples //= len(stream_samples)

Copy link

Choose a reason for hiding this comment

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

Bug: Audio merge can divide by zero

merge_audio_streams divides by len(stream_samples) without guarding against streams being empty. A misconfigured AudioMixerNode with input_channels = [] (or any call site passing an empty list) will crash with a zero-division error during mixing.

Fix in CursorΒ Fix in Web

run: |
# Run this mypy instance against our main package.
uv run mypy --strict .
uv run --all-extras mypy --strict .
Copy link

Choose a reason for hiding this comment

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

Bug: Mypy workflow no longer installs dependencies

The workflow removed uv sync and now runs uv run --all-extras mypy. If uv run doesn’t install [tool.uv].dev-dependencies (including mypy) in this CI context, the job can fail due to missing tools, and --all-extras can also force-install pyaudio, which is fragile in CI even with portaudio19-dev.

Fix in CursorΒ Fix in Web

yield (
self.output_channel,
Message(data=Audio(audio=b"")),
) # Unreachable code
Copy link

Choose a reason for hiding this comment

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

Bug: Unreachable yield statements after raise

There are yield statements placed after raise ValueError in the event_handler methods of both AudioMixerNode and OpenAIRealtimeNode. These lines are unreachable code as noted by the comment "Unreachable code". This appears to be accidentally committed placeholder or debugging code that serves no purpose.

Additional Locations (1)

Fix in CursorΒ Fix in Web

assert isinstance(
action, AgentAction
), f"Action must be AgentAction, got {type(action)}"
complied_actions[sender] = action
Copy link

Choose a reason for hiding this comment

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

Bug: Type signature allows dict but implementation rejects it

The step and astep methods declare a type signature accepting dict[str, AgentAction] | dict[str, dict[str, int | str]], but the implementation asserts that actions must be AgentAction instances. This makes the second union type (dict[str, dict[str, int | str]]) impossible to use, contradicting the type annotation. The comment "Only validate dict inputs (from action space sampling)" also contradicts the assertion that rejects dict inputs.

Additional Locations (1)

Fix in CursorΒ Fix in Web

complied_actions[sender] = AgentAction.model_validate(
action_data, context=context
)
context["sender"] = sender
Copy link

Choose a reason for hiding this comment

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

Bug: Context variable built but never used

In both step and astep methods, a context dictionary is constructed with agent_names, available_action_types, and sender, but it's never passed to any validation or used elsewhere. This appears to be leftover code from an incomplete refactoring where the previous AgentAction.model_validate(action_data, context=context) call was removed but the context construction was not.

Additional Locations (1)

Fix in CursorΒ Fix in Web

if sys.version_info < (3, 11):
pass
else:
pass
Copy link

Choose a reason for hiding this comment

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

Bug: Dead version check code with empty branches

The version check if sys.version_info < (3, 11): has empty pass statements in both branches, making it completely useless. This appears to be leftover code copied from realtime_websocket.py where similar version checks contain actual imports (from typing_extensions import Self vs from typing import Self), but the imports were removed or never added here.

Fix in CursorΒ Fix in Web

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Bug: Subclass parse method incompatible with new context parameter

The PydanticOutputParser.parse method now accepts an optional context parameter, and agenerate passes context via **parse_kwargs when isinstance(output_parser, PydanticOutputParser) is True. However, EnvResponsePydanticOutputParser.parse overrides the parent's method with only a text parameter and no context. Since EnvResponsePydanticOutputParser inherits from PydanticOutputParser, the isinstance check passes, but calling parse(result, context=...) on it raises TypeError: got an unexpected keyword argument 'context'.

sotopia/generation_utils/output_parsers.py#L66-L74

def parse(self, text: str) -> EnvResponse:
# remove trailing commas before ) or ] from text
text = re.sub(r",\s*(\)|\])", r"\1", text)
response = super().parse(text)
if isinstance(response, EnvResponse):
return response
else:
raise ValueError(f"Expected EnvResponse, got {type(response)}")

sotopia/generation_utils/generate.py#L593-L599

# Only PydanticOutputParser supports context parameter
parse_kwargs = (
{"context": context} if isinstance(output_parser, PydanticOutputParser) else {}
)
try:
parsed_result = output_parser.parse(result, **parse_kwargs)

Fix in CursorΒ Fix in Web


@openhands-ai
Copy link

openhands-ai bot commented Dec 16, 2025

Looks like there are a few issues preventing this PR from being merged!

  • GitHub Actions are failing:
    • Pytest in docker

If you'd like me to help, just leave a comment, like

@OpenHands please fix the failing actions on PR #234 at branch `feature/realtime-api`

Feel free to include any additional details that might help me get this PR into a better state.

You can manage your notification settings

@XuhuiZhou XuhuiZhou self-requested a review December 17, 2025 21:56
@XuhuiZhou XuhuiZhou merged commit 6145844 into main Dec 17, 2025
10 checks passed
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.

[FEAT]: Support Realtime API

3 participants