Skip to content

fix(code-sdk-python): README stream loop keeps item.started deltas; SyncMCode raises once in a running loop - #590

Merged
1anZhang merged 1 commit into
mainfrom
fix/py-sdk-stream-readme-sync-close
Nov 4, 2026
Merged

1anZhang merged 1 commit into
mainfrom
fix/py-sdk-stream-readme-sync-close

Conversation

@hetaoBackend

@hetaoBackend hetaoBackend commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Two problems found while testing minimax-code-sdk 0.1.0 from PyPI against mcode 0.6.5 and a real model.

A. README streaming example loses text

The CLI can put the first (or only) contentDelta of an agent_message on item.started. The README loop only read item.updated, so it missed that text. A short reply printed nothing at all:

item.started   {'type': 'agent_message', 'contentDelta': 'pong'}
item.completed {'type': 'agent_message', 'content': 'pong'}
README example output: ''

event["item"] in the same example also fails pyright's default mode (reportTypedDictNotRequiredAccess).

Fix: the README example now uses event.get("item") and reads contentDelta from any agent_message item event, the same way examples/streaming.py already does. I left the event stream itself alone and did not add a synthetic item.updated event: the README and the TS SDK both promise events "passed through unchanged", the TS types already say contentDelta can be on item.started, and a synthetic event would need an invented sequence. The TS README example reads item.completed, so it doesn't have this problem.

B. SyncMCode inside a running event loop raised twice

with SyncMCode() as c: c.start_thread().run("x") inside async def raised the expected RuntimeError. Then __exit__ -> close() raised a second RuntimeError, and coroutine 'Thread.run' was never awaited / coroutine 'sleep' was never awaited warnings were left behind.

Fix: the sync wrappers check for a running loop before they run anything. They close the coroutine that didn't run and raise one RuntimeError that points to the async API. In that case close() just closes the private loop without running it.

Also: MCodeError.items is now annotated as list[ThreadItem].

Tests

  • test_readme_streaming_loop_keeps_delta_on_item_started: fake CLI sends the delta on item.started, and the README loop gets "Hello".
  • test_sync_client_inside_running_loop_raises_once: exactly one RuntimeError and no RuntimeWarning. This test fails on main.
  • uv sync --locked, ruff check, ruff format --check, mypy, and pytest -W error all pass (59 passed, 3 skipped). Opt-in e2e streaming against a real model passes.

Out of scope

There is a separate CLI-side problem. A workspace mismatch on --session, or a model that isn't available, ends mcode exec (exit 4) without exec.completed, and the message ends with "Retry after the connection recovers", which is misleading. The SDK then reports "ended without a result". That is tracked separately.

No version bump and no release.


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

… quiet SyncMCode in a running loop

- README streaming example reads contentDelta from any agent_message item event
  (the CLI puts the first delta on item.started) and uses event.get("item") so
  pyright's default mode passes.
- SyncMCode/SyncThread called inside a running event loop raise one RuntimeError,
  close the un-run coroutine, and close() no longer raises a second error.
- Annotate MCodeError.items.
@hetaoBackend
hetaoBackend requested a review from 1anZhang November 4, 2026 08:26
@1anZhang
1anZhang merged commit 1704e26 into main Nov 4, 2026
20 checks passed
@hetaoBackend
hetaoBackend deleted the fix/py-sdk-stream-readme-sync-close branch November 4, 2026 08:43
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