Skip to content

release: 0.3.0#42

Merged
windsornguyen merged 39 commits intomainfrom
release-please--branches--main--changes--next
Feb 28, 2026
Merged

release: 0.3.0#42
windsornguyen merged 39 commits intomainfrom
release-please--branches--main--changes--next

Conversation

@stainless-app
Copy link
Contributor

@stainless-app stainless-app bot commented Jan 13, 2026

Automated Release PR

0.3.0 (2026-02-28)

Full Changelog: v0.2.0...v0.3.0

Features

  • client: add custom JSON encoder for extended type support (30a7195)
  • client: add support for binary request streaming (48f4cca)
  • runner: dependency-aware parallel tool execution (7e6716f)
  • runner: dependency-aware parallel tool execution (#44) (a72f70f)
  • stream: return StreamResult from stream helpers; fix _compat SyntaxError (#46) (5590e57)
  • stream: return StreamResult from stream_async / stream_sync (e3a55da)

Bug Fixes

  • _compat: remove duplicate by_alias keyword arg (a7deb39)
  • api: add byok provider model (bf52572)
  • api: default auth server (38c637a)
  • api: narrow types (3e16d98)
  • docs: fix mcp installation instructions for remote servers (e4e3619)
  • mcp: filter credentials per-server in _embed_credentials (aff8b1c)
  • mcp: filter credentials per-server in _embed_credentials (#43) (baa0239)
  • mcp: restore pydantic v1 compatibility for wire aliases (37e69b2)
  • runner: allow local tool execution in mixed MCP+local scenarios (5d0ce6d)
  • runner: inject server tool results into conversation for mixed tool calls (288b70e)
  • runner: preserve thought_signature in tool call accumulation and extraction (77e5958)
  • runner: server tool results, mixed-tool execution, thought_signature passthrough (#45) (637d9b8)
  • runner: skip early break when local tools need execution alongside MCP (ad7379b)

Chores

  • api: small type fixes (2268aff)
  • ci: add missing environment (0ec49ed)
  • ci: bump uv version (b73fa3b)
  • ci: upgrade actions/github-script (cf53a9e)
  • format all api.md files (ead37d4)
  • internal: add request options to SSE classes (df6a0e6)
  • internal: bump dependencies (696aacf)
  • internal: fix lint error on Python 3.14 (eace981)
  • internal: make test_proxy_environment_variables more resilient (e6b7ee4)
  • internal: make test_proxy_environment_variables more resilient to env (d368d31)
  • internal: remove mock server code (dc1e10e)
  • internal: update actions/checkout version (c72dfca)
  • runner: strip commented-out production version and banner comments from core.py (59350e3)
  • update mock server docs (db13895)

Styles

  • tests: flatten test classes to module-level functions (57dc181)

Refactors

  • test: tighten typing in MCP request regression tests (3c1d415)

This pull request is managed by Stainless's GitHub App.

The semver version number is based on included commit messages. Alternatively, you can manually set the version number in the title of this pull request.

For a better experience, it is recommended to use either rebase-merge or squash-merge when merging this pull request.

🔗 Stainless website
📚 Read the docs
🙋 Reach out for help or questions

@stainless-app
Copy link
Contributor Author

stainless-app bot commented Jan 13, 2026

🧪 Testing

To try out this version of the SDK:

pip install 'https://pkg.stainless.com/s/dedalus-sdk-python/baa02390c55e622ca8e632e584580a105c478c96/dedalus_labs-0.2.0-py3-none-any.whl'

Expires at: Mon, 30 Mar 2026 21:17:15 GMT
Updated at: Sat, 28 Feb 2026 21:17:15 GMT

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from ac5c5d9 to c72a9be Compare January 16, 2026 18:31
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from c72a9be to 00246c5 Compare January 22, 2026 03:58
*,
cast_to: Type[ResponseT],
body: Body | None = None,
content: BinaryTypes | None = None,
Copy link

Choose a reason for hiding this comment

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

Iterator content silently lost on request retry

Medium Severity

When content is an Iterable[bytes] (like a generator), the iterator is consumed on the first request attempt. If a retryable error occurs, the retry logic uses model_copy which performs a shallow copy, so options.content still references the same exhausted iterator. Subsequent retry attempts send an empty request body. This is exacerbated by DEFAULT_MAX_RETRIES being increased from 0 to 2 in this same PR. Users passing generator-based content could experience silent data loss on transient failures.

Additional Locations (1)

Fix in Cursor Fix in Web

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from 00246c5 to f4bfcf4 Compare January 23, 2026 18:15
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from f4bfcf4 to 120f4f7 Compare January 28, 2026 16:37
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from 120f4f7 to b02a9df Compare February 7, 2026 10:42
@cursor
Copy link

cursor bot commented Feb 7, 2026

PR Summary

Medium Risk
Touches core request/serialization and runner tool-execution paths (new retry defaults, raw content support, dependency-aware scheduling, and MCP credential embedding), which can change runtime behavior across most API calls. CI/test harness changes (removing Prism mock) may reduce coverage for request-shape regressions.

Overview
Releases v0.3.0 with new API surface and behavior changes.

Adds new client resources for POST /v1/ocr (client.ocr.process) and POST /v1/responses (client.responses.create), updates audio speech typing to support custom voices/new TTS model, and sets a default as_base_url plus an optional X-Provider-Model header.

Updates the HTTP client to support raw/streaming binary request bodies via a new content parameter (sync/async) with validation + deprecation of body=bytes, and switches JSON body serialization to a custom encoder (openapi_dumps) to handle types like datetime and pydantic.BaseModel.

Refactors DedalusRunner to accept/forward a broader set of chat-completions kwargs, preserves thought_signature during streamed tool-call accumulation, and introduces a dependency-aware local tool scheduler (_scheduler.py) that can run independent tools concurrently. MCP credential embedding now attaches only per-server credentials (via slug_to_connection_name) and MCP server wire serialization restores Pydantic v1 compatibility.

Operational updates: default retries increased to 2 with longer backoff, CI actions/uv versions bumped (and PyPI publish job set to production environment), docs updated (MCP install URLs and retry defaults), formatting now targets all api.md files, and Prism mock-server scripts/test setup removed.

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

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from b02a9df to 3c98764 Compare February 7, 2026 11:13
[],
steps,
verbose=exec_config.verbose,
)
Copy link

Choose a reason for hiding this comment

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

Missing assistant message before tool execution in streaming paths

High Severity

Both streaming paths (_execute_streaming_async and _execute_streaming_sync) call the scheduler's execute_local_tools_async/execute_local_tools_sync without first appending an assistant message with tool_calls to the messages list. The scheduler's own docstring explicitly states the caller is responsible for this. The non-streaming paths (_execute_tool_calls at line 1204, _execute_tool_calls_sync at line 1229) correctly append {"role": "assistant", "tool_calls": ...} before calling the scheduler. The old streaming code also did this but the line was removed during the refactoring. This produces a malformed conversation (tool messages without a preceding assistant message), which will cause the API to reject subsequent requests.

Additional Locations (1)

Fix in Cursor Fix in Web

# Collect MCP tool results emitted by the server
chunk_extra = getattr(chunk, "__pydantic_extra__", None) or {}
if isinstance(chunk_extra, dict) and "mcp_tool_results" in chunk_extra:
mcp_tool_results_from_server = chunk_extra["mcp_tool_results"]
Copy link

Choose a reason for hiding this comment

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

Collected MCP tool results variable is never used

Low Severity

mcp_tool_results_from_server is assigned in both _execute_streaming_async and _execute_streaming_sync but is never read after assignment. The variable is dead code — the collected MCP tool results are silently discarded. Given the PR includes a fix for "inject server tool results into conversation for mixed tool calls," this may represent an incomplete implementation for the streaming paths.

Additional Locations (1)

Fix in Cursor Fix in Web

@cursor

This comment has been minimized.

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from 3c98764 to b8e048e Compare February 7, 2026 15:33
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from f20bb1f to 36b0123 Compare February 12, 2026 16:56
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from 36b0123 to afba00e Compare February 13, 2026 00:06
exclude=exclude,
exclude_unset=exclude_unset,
exclude_defaults=exclude_defaults,
exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias)
Copy link

Choose a reason for hiding this comment

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

Default by_alias change breaks request serialization of aliased fields

Medium Severity

The model_dump helper in _compat.py changed its by_alias default from hardcoded True to None (effectively False). The _transform_recursive function in _transform.py calls model_dump(data, exclude_unset=True, mode="json") without passing by_alias, relying on the previous default. This breaks serialization of Pydantic models with field aliases — notably JSONSchema.schema_ (aliased to "schema") will now serialize as "schema_" instead of "schema", sending incorrect field names to the API.

Fix in Cursor Fix in Web

@cursor
Copy link

cursor bot commented Feb 13, 2026

Bugbot Autofix prepared fixes for 1 of the 1 bugs found in the latest run.

  • ✅ Fixed: Default by_alias change breaks request serialization of aliased fields
    • Changed the by_alias parameter default from None to True in model_dump() to restore the original behavior where Pydantic field aliases are used during serialization.

Create PR

Or push these changes by commenting:

@cursor push 018c6c55a4
Preview (018c6c55a4)
diff --git a/src/dedalus_labs/_compat.py b/src/dedalus_labs/_compat.py
--- a/src/dedalus_labs/_compat.py
+++ b/src/dedalus_labs/_compat.py
@@ -139,7 +139,7 @@
     exclude_defaults: bool = False,
     warnings: bool = True,
     mode: Literal["json", "python"] = "python",
-    by_alias: bool | None = None,
+    by_alias: bool = True,
 ) -> dict[str, Any]:
     if (not PYDANTIC_V1) or hasattr(model, "model_dump"):
         return model.model_dump(
@@ -154,7 +154,7 @@
     return cast(
         "dict[str, Any]",
         model.dict(  # pyright: ignore[reportDeprecated, reportUnnecessaryCast]
-            exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias)
+            exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=by_alias
         ),
     )

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from afba00e to 8d6900c Compare February 19, 2026 16:03
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from 8d6900c to e719ab6 Compare February 23, 2026 13:29
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.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is ON. A Cloud Agent has been kicked off to fix the reported issues.

[],
steps,
verbose=exec_config.verbose,
)
Copy link

Choose a reason for hiding this comment

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

Streaming tool results not recorded

Medium Severity

The streaming local-tool execution path passes fresh empty lists for tool_results and tools_called into execute_local_tools_async()/execute_local_tools_sync(), so successful executions in streaming mode are never reflected in the runner’s tracking structures.

Fix in Cursor Fix in Web

sorter.add(call_id, *deps)

sorter.prepare()
return calls_by_id, sorter
Copy link

Choose a reason for hiding this comment

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

Tool scheduler can collide on empty ids

High Severity

_parse_pending_calls() uses call_id = tc.get("id", "") as the TopologicalSorter node key and as the calls_by_id key. If any tool call lacks an id, multiple calls collapse onto the same empty-string id, overwriting entries and producing incorrect dependency ordering and tool_call_id references in emitted role="tool" messages.

Fix in Cursor Fix in Web

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from e719ab6 to 9c9dc29 Compare February 23, 2026 20:28
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from 9c9dc29 to 6963417 Compare February 24, 2026 17:44
@windsornguyen windsornguyen force-pushed the release-please--branches--main--changes--next branch from e50bab2 to 6963417 Compare February 28, 2026 21:06
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from 6963417 to b1148aa Compare February 28, 2026 21:06
windsornguyen and others added 3 commits February 28, 2026 13:15
Merge latest next into fix/mcp-credential-filtering and resolve request.py/wire.py conflicts while preserving per-server credential embedding behavior.
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from b1148aa to 9ea2655 Compare February 28, 2026 21:16
@windsornguyen windsornguyen merged commit 1aae853 into main Feb 28, 2026
6 of 8 checks passed
@stainless-app
Copy link
Contributor Author

stainless-app bot commented Feb 28, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants